DevPilot 是一个面向 Agent Engineering 学习与实践的练习仓库:一个从零搭建的最小 Agent Runtime,加上多个在它之上组合出的应用层 Agent(Research / RAG / Memory / Planning / Resume)。
它不是 LLM API 的薄封装。项目从 Agent 运行时真正需要回答的工程问题出发:Agent Loop 如何驱动执行、Tool Calling 如何调度与隔离错误、Context / Session 如何进入下一次 LLM 请求、State / Checkpoint 在哪里划边界、Verification 如何成为交付闸门、Retry 如何被有界策略约束。先把这些基础能力显式搭出来,再复用它组合具体 Agent。
其中 Resume Agent V1 是当前最完整的应用层 Demo:它演示了“用户资料 + 招聘 JD → 事实约束下的生成 → 确定性验证 → Markdown 简历”这样一个可运行的垂直闭环。
定位:个人 Agent Engineering practice / portfolio 项目,刻意保持小而可读,不是商业产品。
- 语言 / 环境:Python 3.12,纯异步(asyncio)。
- 运行时基础能力(Core,位于
devpilot/根级模块):Agent Loop、Tool Calling、Session / Projection / RequestBuilder、LLM Provider 抽象、State / Phase、Checkpoint / Recovery、ExecutionStore / TraceStore。 - 工程闭环能力:Verification、Retry / Stop Condition、Planning / Replan、Evaluation(确定性 metric)。
- 应用层 Agent:Research Agent、RAG Agent、Memory Agent、Resume Agent V1(目录见 Project Structure)。
- 依赖:核心代码仅依赖
openaiSDK(真实 LLM 调用)与mcp(MCP 接入),其余为标准库;Evaluation 额外依赖deepeval。
我希望能真正理解 Agent Engineering 中“运行时”层面的问题,而不只是停留在“调用一次 LLM”:
- Agent Loop 如何驱动 Turn / Step,如何避免无界循环(max_iterations、终态语义);
- Tool Calling 如何注册、调度(serial / parallel),并在出错时隔离而不是击穿 Runtime;
- Context / Session 如何被组织、投影并进入下一次 LLM 请求;
- State / Checkpoint / Recovery 的职责边界与恢复语义;
- Verification 如何成为应用层交付闸门;
- Retry / Replan 如何受 bounded policy 约束;
- 应用层 Agent 如何复用同一套 Core,而不是为每个场景重写 Runtime。
这个项目把上述边界用尽量小的代码量显式实现,并用测试锁定“这些契约确实成立”。
DevPilot 分为两层:与具体应用无关的 Core Runtime,和复用 Core 的应用层 Agent。
flowchart TB
subgraph CORE["Core Runtime(devpilot/ 根级模块,与具体应用无关)"]
direction TB
C0["Core Runtime"]
C0 --> C1["Runtime / AgentLoop"]
C0 --> C2["Tool / ToolRegistry / ToolScheduler"]
C0 --> C3["Session / Context / RequestBuilder"]
C0 --> C4["Provider"]
C0 --> C5["State / Checkpoint / Recovery"]
C0 --> C6["ExecutionStore / TraceStore"]
end
C0 -->|"shared foundation"| A0
subgraph APP["Application Layer(应用层)"]
direction TB
A0["Application Layer"]
A0 --> A1["Research"]
A0 --> A2["RAG"]
A0 --> A3["Memory"]
A0 --> A4["Planning"]
A0 --> A5["Resume Agent V1"]
end
A1 --> G["普通 Agent 路径:Agent → Runtime + AgentLoop → Tool / Session / Provider"]
A2 --> G
A3 --> G
A5 --> R["正式 Resume Workflow:ResumeService → Document → Fact → JD → Matching → ResumeModel → Verification → Delivery"]
C4 -. "可选 LLM 调用" .-> R
两层之间有两种真实存在的执行方式(与代码一致,需要区分):
- Research / RAG / Memory,以及 Resume 的 Prompt Demo,以
Agent(内部是 Runtime + AgentLoop)作为执行载体:注册 Tool + 注入 Skill prompt,复用同一套 Tool / Session / Provider。Planning 作为应用层的 Planner → Executor → Verifier → Replanner / Retry 编排,不新建 Runtime。 - Resume Agent 的正式入口是应用层的结构化 Resume Workflow(
run_resume_workflow/ResumeService/ CLIresume):它在应用层编排 Document → Fact → JD → Matching → ResumeModel → Verification → Delivery,只复用 Core 的 LLM Provider 抽象做可选 LLM 调用,不经过 AgentLoop / ToolScheduler,也没有为 Resume 重写第二套 Runtime。
(主 Demo:用户资料 + 招聘 JD → Markdown 简历)
flowchart LR
A["Profile + JD(TXT / Markdown / plain text,多文档)"] --> B["Document Parsing"]
B --> C["Fact Extraction(逐行 verbatim → UserFact,保留来源)"]
C --> D["UserProfile(User Facts = Source of Truth)"]
D --> E["JD Analysis(→ JDRequirement)"]
E --> F["Requirement Matching(STRONG / PARTIAL / MISSING)"]
F --> G["Resume Generation(→ ResumeModel / ResumeStatement,绑定 fact / requirement)"]
G --> H["Deterministic Verification"]
H --> I{"Delivery Gate"}
I -- "pass" --> J["Markdown Resume + ResumeVersion"]
I -- "fail" --> K["阻止交付:不渲染 / 不建版本 / 不写文件"]
核心设计原则(与代码一致):
- User Facts 是 Source of Truth:事实抽取为逐行 verbatim,保留来源(source_document_id / 文档位置);生成内容必须绑定已有事实,不允许模型凭空增加公司、项目、技术、数字、职责或成果。
- 可追溯(provenance):每条 ResumeStatement 记录支撑它的 UserFact id 与对应的 JD requirement id;用
--annotate可在 Markdown 注释里输出 provenance。 - Matching 三档:STRONG / PARTIAL / MISSING。MISSING 表示“证据缺口”而不是错误;它可以驱动 gap-driven interview(追问 → 用户补充新事实 → 重新匹配)。
- Verification = Delivery Gate:error 级问题(空简历 / 无来源陈述 / 缺小节等)会阻止交付——不渲染、不创建 ResumeVersion、不写文件;warning(疑似新增词/数字、JD 必须项缺口等)需要人工确认。
- 一个 UserProfile + 多个 JD → 多个 ResumeVersion:同一个
ResumeService可面向不同 JD 多次运行,每次生成独立的 ResumeVersion(单次运行接收一个 JD,对应run()/run_from_texts()的签名)。
结构上,devpilot/resume/ 由领域模型(Document / UserFact / UserProfile / JD / ResumeModel…)、parsers(文本解析)、skills(FactExtraction / JDAnalysis / Matching / Interview / Generation)、verifier、renderer、service(编排)组成。它是 Application Layer,不修改 Runtime / AgentLoop / Session / Provider / ToolRegistry。
仓库当前没有 pyproject.toml、requirements.txt 或 setup.py 等标准安装入口。使用 Python 3.12;离线 Resume Demo 仅依赖标准库,无需额外安装。需要真实 LLM / MCP 时再安装可选依赖:
git clone https://github.com/RainCongeals/DevPilot.git
cd DevPilot
python --version # Python 3.12
# 仅需真实 LLM / MCP 时执行;离线 Resume Demo 不需要额外安装
python -m pip install openai mcp这是一个 offline deterministic Resume Agent V1 vertical slice:不需要 API Key,也不需要网络。
Input: profile.md + jd_backend.txt
→ Document Parsing → Fact Extraction → UserProfile
→ JD Analysis → Matching(STRONG / PARTIAL / MISSING)
→ ResumeModel → Deterministic Verification → Delivery Gate
Output: resume.md(Verification 通过时)
从仓库根目录运行:
# 从仓库根目录运行
python -m devpilot resume \
--profile examples/resume_samples/profile.md \
--jd examples/resume_samples/jd_backend.txt \
--out resume.md- 默认无 Key 时走确定性链路:解析 → 事实抽取 → JD 分析 → 匹配 → 生成 → 验证 → 交付,全程不调用真实 LLM。
- 运行后在仓库根目录生成
resume.md:只有 Verification 通过才会写入;失败会打印原因并阻止交付。 - 等价脚本版:
python examples/resume_pipeline_demo.py --out resume.md。 - 若设置了
OPENAI_API_KEY/DEEPSEEK_API_KEY,会启用可选的 LLM 步骤(事实类别复核 + 表达润色),但不会改写事实内容与 provenance。 - 样例输入(
devpilot/resume/samples.py内置样例、examples/resume_samples/文件)均为虚构数据,方便直接跑通。 - 环境:Python 3.12。纯离线 demo 无需额外安装;真实 LLM / MCP 需要
pip install openai mcp;Evaluation 需要pip install deepeval。
成功运行后,输出/结果会包含 JD requirements、STRONG / PARTIAL / MISSING matching、结构化 ResumeModel / 生成简历和 Verification 结果;Verification 通过时会交付 resume.md,否则不渲染、不创建 ResumeVersion、不写文件。
(工程点说明,不逐条罗列开发历史)
- Agent Loop:把“驱动”与“单步行动”分开。
Runtime负责生命周期:启动 Turn、在max_iterations内推进、决定终态(COMPLETED / FAILED / STOPPED);AgentLoop只执行单步:从 Inbox 认领输入 → Projection 投影 → RequestBuilder 构造请求 → 调用 LLM → 执行工具或产出最终文本。分开之后,Checkpoint / Recovery / Trace 才能挂到明确的边界上。 - Tool Calling:注册、调度、错误隔离。Tool 以唯一 name 注册进
ToolRegistry;ToolScheduler支持 serial / parallel 调度;工具抛错由错误边界转成ToolResult(success=False)回到对话流,而不是让整个 Runtime 崩溃。Tool 还声明 execution_mode(serial / parallel)与 effect(read_only / idempotent / side_effect),为 Recovery 决策提供依据。 - Context / Session:历史与请求之间的显式边界。
Session保存对话历史(含 tool call / tool result / reasoning_content);每次请求前由Projection生成独立的RuntimeContext快照,再由RequestBuilder组装 provider 请求。历史不直接裸传给 LLM,中间有明确的投影边界。 - Provider 抽象:离线可测 + 真实可切换。
EchoProvider(离线、确定性)让核心逻辑不依赖外部 API 即可测试;OpenAIProvider/DeepSeekProvider走真实模型,DeepSeek thinking 模式的reasoning_content会在多轮 tool calling 中回传。ProviderFactory按显式优先级选择(显式 provider → provider_name → 环境变量 → Echo)。 - Verification 作为交付闸门。在 Resume 场景,Verifier 在“生成之后、渲染 / 写文件之前”执行,error 级问题直接阻断交付;验证与生成分离,验证器只判断、不修改内容。
- Retry / Replan 受 bounded policy 约束。Retry 只有两个停止条件:验证成功,或达到
max_retries上限;Planning 提供 Planner → Executor → Verifier → Replanner / Retry 的有界闭环,避免无界的“自我修正”循环。 - 可观测性分层。ExecutionStore 记录每次 ToolCall 的执行事实(NOT_STARTED / RUNNING / SUCCEEDED / FAILED),TraceStore 记录 Run / Turn / Step / LLM / Tool 的事件轨迹,TraceAnalyzer 做只读分析;Trace 不保存 Secret 或完整 prompt,属于观察层而非控制层。
- 应用层复用 Core。新增“一种 Agent”时,主要工作是“注册哪些 Tool + 注入什么 Skill 方法论”,而不是复制 Runtime;Resume Agent 进一步展示了“结构化应用层编排 + 复用 Provider 抽象”这种不依赖 AgentLoop 的形态。
当前离线测试结果(本轮复核,未设置外部 API Key,Python 3.12.10):
pytest: 656 passed, 9 skipped(0 failed)
- 9 个 skipped 全部是外部 / 真实 LLM 集成用例,默认 gated:需设置
OPENAI_API_KEY/DEEPSEEK_API_KEY(部分还需*_E2E=1)才运行;没有 Key 时跳过,而不是伪造成功。 - 覆盖范围:Runtime / AgentLoop 生命周期、Tool 调度与错误边界、Session / Projection / Request(含 thinking reasoning_content)、Checkpoint / Recovery、Trace、Memory / RAG / Planning、Resume Agent 的 workflow contract、Verification Delivery Gate、回归测试、CLI E2E。
- 重要说明:这些测试验证的是确定性行为、workflow 契约、验证闸门与回归,它们不能证明模型输出“没有幻觉”。Resume 的防编造体现为“事实绑定 + 确定性校验 + 人工确认警告”,而不是“证明无幻觉”。
运行测试:
python -m pytest -q
# 或
python -m unittest discover -s testsDevPilot/
├── devpilot/ # 核心包
│ ├── agent.py / runtime.py / loop.py # Agent 组装、Runtime、AgentLoop
│ ├── session.py / projection.py / request.py / runtime_context.py # Context/Session
│ ├── tool.py / tool_registry.py / tool_scheduler.py / tool_error.py # Tool Layer
│ ├── checkpoint.py / recovery.py / state.py / phase.py / turn.py / inbox.py / execution.py
│ ├── trace.py / trace_analysis.py # 运行轨迹(观察层)
│ ├── llm_provider.py / llm_client.py / llm_config.py / llm_error.py / llm_stream.py
│ ├── provider_factory.py / openai_provider.py / deepseek_provider.py
│ ├── resume/ # Resume Agent V1(应用层)
│ ├── research/ # Research Agent(应用层)
│ ├── rag/ # RAG(应用层,本地文档关键词检索)
│ ├── memory/ # Memory(应用层,跨 Session)
│ └── planning/ # Planning / Replan / Retry(应用层)
├── examples/ # 可运行示例 + Resume 样例输入(examples/resume_samples/)
├── tests/ # 单元 / 集成 / E2E / 回归测试
└── evaluation/ # DeepEval 最小评估层
devpilot/ 根级模块构成 Core;devpilot/resume/、devpilot/research/、devpilot/rag/、devpilot/memory/、devpilot/planning/ 是应用层子包,复用 Core 而不修改 Runtime。
与当前代码一致的诚实边界:
- PDF / DOCX:目前只能识别类型(占位),解析器尚未接入——直接输入会抛
UnsupportedDocumentTypeError;输出渲染目前只支持 Markdown。 - Semantic verification 尚未实现:
ResumeVerifier.verify_semantic(LLM-as-Judge 方向)只是接口占位,没有实现。 - DeepEval Resume 专项评估尚未完成:
evaluation/目前是最小确定性评估链路,尚无 Resume-specific cases。 - TraceStore 与 Resume audit 尚未完全统一:Resume workflow 的 audit 目前是结构化列表,与 Core TraceStore 是两套记录。
- CJK matching 可能误报:Matching 基于关键词与中文 bigram,可能出现 false positives,需要人工确认。
- Deterministic verifier 不能证明“绝对无幻觉”:它通过“事实绑定 + 启发式检查(疑似新增词/数字)”给出需要人工确认的 warning,而不是语义级证明。
- Interactive interview CLI 尚未完成:gap-driven interview 的核心逻辑(问题生成、回答转事实、重新匹配)已实现,但交互式 CLI 对话流程尚未完成。
- PDF / DOCX robust parsing(及对应 renderer)
- Stronger semantic verification(LLM-as-Judge 方向)
- Resume-specific evaluation cases
- TraceStore 与 Resume audit 的统一
- Human-in-the-loop review
- GUI / Web UI(明确为未来方向,非当前目标)
这是一个 Agent Engineering practice / portfolio 项目,希望向读者展示:
- Agent Runtime 的分层与生命周期设计(Runtime / AgentLoop / State / Phase / Checkpoint / Recovery)
- Tool orchestration(Registry / Scheduler / 错误边界 / 副作用分类)
- Context / State / Session 的边界与可观测性分层(ExecutionStore / TraceStore)
- Verification 作为交付闸门的工程实践
- Planning / Replan / Retry 的有界闭环
- Application-layer Agent 设计:如何在不修改 Runtime 的前提下组合出可工作的 Agent(以 Resume Agent V1 为主线案例)
它不是、也不包装成成熟商业产品;它以“小、可读、可测试、边界清晰”为目标,方便读者快速理解每一层的职责与取舍。
MIT License,见 LICENSE。