Skip to content

Repository files navigation

Agent Campus

Agent Campus 是一个基于 LangGraph 的多 Agent 校园社会模拟器。

项目目标

让具有不同人格、目标、记忆和资源限制的 AI 角色,在一个持续运行的校园环境中互动,并观察他们如何合作、冲突、传播信息和完成任务。

MVP 范围

  • 3 个 AI 角色
  • 1 个校园场景
  • 7 种基础行动:移动、交谈、争吵、上课、参加活动、交换物品、睡觉
  • 短期记忆和简单长期记忆
  • 可回放的模拟过程
  • 基础行为评测

计划技术栈

  • Python
  • LangGraph
  • LangChain
  • Pydantic
  • SQLite(原型阶段)
  • FastAPI(后续 API)

当前状态

已完成第一个 MVP:

  • 3 个角色:Alice、Bob、Charlie
  • 1 个校园场景:宿舍、教室、图书馆、食堂、学生活动中心
  • 7 种行动:移动、交谈、争吵、上课、参加活动、交换物品、睡觉
  • 4 种场景信息生成器:课表、时间、天气、活动
  • LLM 可自主选择 get_scheduleget_timeget_weatherget_activities 工具并填写参数;查询结果会回到下一次观察中
  • 基于规则的行动验证和事件日志
  • 基于 LangGraph 的观察 → LLM 决策 → 执行流程
  • 有界 ReAct 循环和 finish_turn 主动结束动作
  • 交谈会把对话请求交给对方的 LLM,由对方自主选择是否继续回复;回复可形成有限长度的对话链,不会自动生成回复
  • 基于历史对话和事件的长期记忆检索
  • LLM、Embedding、RAG 和 Durable Execution 的异步调用;独立记忆源使用 asyncio.gather 并行检索,Agent 状态提交仍保持串行
  • 独立的校园公开知识库种子数据,覆盖课程资料、校园规则、社团活动、课程表、校园地图和角色公开信息
  • 基于 SQLite checkpoint 的 Durable Execution
  • 完整的单元测试覆盖行动、图、记忆和 RAG 评测

本地运行

conda activate agent-campus
pytest -q
python -m agent_campus.main --rounds 3
python -m agent_campus.main --rounds 3 --thread-id campus-demo --state-db campus.sqlite --max-react-steps 3 --max-decision-retries 2
python -m agent_campus.main --duration-days 3 --thread-id campus-3-days --state-db campus.sqlite

Docker 运行

项目提供 Dockerfilecompose.yaml。Docker Desktop 启动后,在项目根目录执行:

cp .env.example .env

然后编辑 .env,填写 DEEPSEEK_API_KEYZHIPUAI_API_KEY.env 已被 Git 忽略,不会提交密钥。

构建并运行 3 个模拟回合:

docker compose up --build

SQLite checkpoint 保存在 runtime/agent_campus.sqlite,本地 Qdrant 数据保存在 data/qdrant/,两者通过 Compose volume 持久化。首次使用或校园知识库更新后,先构建索引:

docker compose run --rm agent-campus python -m agent_campus.rag_index --qdrant-path /app/data/qdrant

常用操作:

docker compose ps
docker compose logs -f agent-campus
docker compose down

需要调整运行参数时,可以覆盖 Compose 的默认命令,例如:

docker compose run --rm agent-campus python -m agent_campus.main \
  --duration-days 3 \
  --thread-id campus-3-days \
  --state-db /app/runtime/agent_campus.sqlite \
  --qdrant-path /app/data/qdrant

运行前需要在 Conda 环境中设置 DEEPSEEK_API_KEYZHIPUAI_API_KEYZHIPUAI_API_KEY 用于 embedding-3 语义记忆检索,EMBEDDING_DIMENSIONS 可选值为 25651210242048,默认使用 1024--rounds 控制本次运行的回合数,每回合结束后世界时间推进 30 分钟;--duration-days 按模拟时间运行指定天数,并在最后一步自动截断到准确的目标时间;两者不能同时使用。默认既未指定时长也未指定回合数时运行 1 回合。--max-react-steps 限制每个 Agent 回合最多执行多少次 ReAct 步骤;LLM 可以通过 finish_turn 提前结束。--thread-id 标识一个可恢复的模拟会话,使用同一个 thread_idstate-db--duration-days 再次运行时,会继续到原先保存的模拟时间目标,不会重复追加同样的天数。LLM 通过工具调用选择角色行动,模拟器负责统一执行并记录结果。API 密钥只保存在本地 Conda 环境变量中,不写入项目文件。

独立校园知识库

校园公开资料原始文件位于 data/campus_knowledge/:Markdown 保存正文,metadata.json 保存文档 ID、类别和 tags。src/agent_campus/campus_knowledge.py 只负责加载和校验这些独立语料,不写入 WorldState,也不参与模拟状态 checkpoint。后续实现 RAG 时,可直接使用 create_default_campus_documents() 获取文档,再为每条文档建立向量索引;CampusDocument.as_retrieval_text() 提供了带类别和标题的检索文本。

知识库切分由 src/agent_campus/chunking.py 负责:优先保留段落、规则条目和句子边界,默认每个 Chunk 最多 600 个字符、重叠 80 个字符,并继承 parent_id、类别、标签和来源文件等 metadata。切分后的 KnowledgeChunk.as_retrieval_text() 可直接送入 embedding-3metadata() 可作为 Qdrant payload。

Chunk 的 Embedding 由 src/agent_campus/embedding_pipeline.py 负责:embed_default_campus_knowledge() 会加载、切分并批量调用 embedding-3,返回带向量和 metadata 的 EmbeddedChunksave_embedded_chunks() 可将本地构建结果保存到 data/embeddings/,该目录已加入 .gitignore,不会提交向量缓存。

首次使用或知识库内容更新后,先构建 Qdrant 索引:

python -m agent_campus.rag_index --qdrant-path data/qdrant

该命令会加载 data/campus_knowledge/、切分文档、调用 Embedding API 并幂等写入本地 Qdrant collection。

Qdrant 接入由 src/agent_campus/qdrant_store.py 负责。当前使用 Qdrant 本地持久化模式,upsert_embedded_chunks() 会创建 1024 维 cosine collection,并将 Chunk 正文和 metadata 写入 payload;search_qdrant() 用于相似度检索。生产部署时可将 open_local_qdrant() 替换为远程 Qdrant 连接。

CombinedMemoryRetriever 会合并角色私有长期记忆和 Qdrant 校园公开资料,并由 main.py 注入现有 StateGraph 的 retrieve_memory 节点;LLM 会在同一个 retrieved_memories 上下文中同时获得两类信息。

上下文压缩

每个 Agent 会独立估算自己的语义摘要、历史记忆和已学知识的上下文量。只有超过阈值时,才额外调用一次 DeepSeek LLM,将这些内容整理为事实准确的语义摘要;摘要会写入 Agent 状态,并参与后续长期记忆检索,已被摘要覆盖的原始记忆和知识会被清理。未超过阈值时不会调用摘要 LLM,也不会对上下文做确定性截断。

默认阈值约为 2000 个估算 token,可通过 --context-compression-threshold-tokens 调整,例如:

python -m agent_campus.main --rounds 3 --context-compression-threshold-tokens 3000

阈值使用约 2 字符/token 的本地估算,不依赖额外 tokenizer。WorldState.events 仍会保留用于模拟回放;摘要调用失败时会抛出错误,不会静默删除原始记忆。

长期人格演化

每个 Agent 的 personality 是稳定的人格基线;personality_state 按 MBTI 的 E/IS/NT/FJ/P 四组维度保存连续偏好和基线类型。行动成功后只会累积人格证据,不会立即改写人格。完整回合结束时,只有在至少积累 5 次一致经历且距离上次更新达到模拟 7 天后,才会进行一次人格整合;单次整合的单项变化最多为 0.05

四组维度在模拟中的含义是:E/I 表示偏好社交互动还是独处思考,S/N 表示偏好具体事实还是抽象可能性,T/F 表示偏好逻辑分析还是价值与关系,J/P 表示偏好计划结构还是灵活应变。系统用 0.0–1.0 保存每个正向字母的偏好强度,低于 0.5 时显示为对应的另一端;这是一种用于行为模拟的简化模型,不代表心理学诊断。

默认角色类型为:Alice=ISTJ、Bob=ENFP、Charlie=ISTJ。成功经历会形成 MBTI 证据:talk 增加 E/Fargue 增加 Ttrade 增加 F/Jattend_class 增加 S/Jjoin_event 增加 E/N。达到阈值后,当前 MBTI 类型和自然语言人格描述会重新渲染,并注入后续 LLM 决策、对白和事件效果提示词。

人格更新记录在 personality_state.history 中,并随 WorldState 一起进入 SQLite checkpoint。LLM 决策使用由结构化人格状态渲染出的动态人格描述,而工具规则和校园世界规则保持不变。因此,一次争吵通常只影响记忆或短期状态,持续多天的重复经历才会改变角色的行为倾向。

多维事件效果与角色对白

LLM Agent 的人物交流分为两步:角色先根据自身人格、目标人物人格、当前好感和信任生成最终对白;随后 LLMEventEffectResolver 将对白解析为受限的结构化效果。效果可以同时包含记忆、好感、信任、精力、课程知识和技能成长。模拟器仍由规则层校验位置、精力最低消耗、物品交换和数值上下限,LLM 不直接修改 WorldState

当前示例包括:argue_with 会让双方留下争吵记忆并降低好感和信任;attend_class 会获得课程知识,并根据 persistence 增加技能等级;友好交谈和物品交换会分别产生关系与信任变化。夜间 sleep 会把角色精力恢复到 100;精力不足时,决策工具不会提供聊天、争吵和交易。LLM 解析失败时会退回 src/agent_campus/effects.py 中的安全规则效果,不会阻止模拟继续运行。

基于当前真实 Embedding 评测集,RAG 默认过滤 cosine 相似度低于 0.60 的 Chunk,并按 parent_id 去重;可通过 --rag-score-threshold 调整阈值。该阈值在当前 5 个正例和 2 个无答案样本上达到 5/5 命中、2/2 正确拒答。主程序启用强制证据模式:过滤后没有任何有效上下文时,Agent 会直接结束回合并报告“无法可靠回答”,不会调用 LLM 生成猜测答案。使用 run_agent_turn()run_llm_agent_turn() 时,可传入 retrieval_required=True 启用同样的拒答策略。

RAG 检索质量验证可运行:

python -m agent_campus.rag_evaluation
# 对比多个相似度阈值
python -m agent_campus.rag_evaluation --score-thresholds 0.2,0.3,0.35,0.4,0.5

该评测覆盖五类应该命中的问题和两类预期无答案的问题,分别统计 answerable hit rate、正确拒答率和 false positive rate;单阈值运行时默认要求 answerable hit rate 至少为 0.8,且不允许无答案问题产生召回结果。多阈值模式只输出对比结果,不作为失败门禁。

真实 DeepSeek Agent 的 RAG 对照评测可运行:

python -m agent_campus.rag_ablation

它会对相同场景分别运行 RAG 开启和关闭两组 Agent,比较目标行动成功率;结果保存到 data/evaluations/,该目录不提交到 Git。

About

A multi-agent campus social simulation built with LangGraph, featuring memory, RAG, personality evolution, and durable execution.

Resources

Stars

101 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages