Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

编程智能体(Coding Agent)

一个运行在本地、通过与大语言模型交互来自主读写文件、执行命令、完成编程任务的智能体——类似一个极简的 Claude Code / Codex / OpenCode。

  • 模型:DeepSeek(OpenAI 兼容接口,默认 deepseek-v4-flash)
  • 语言:Python 3.10+
  • 依赖:零第三方依赖——连 HTTP 层、SSE 流式解析、token 估算、单元测试,全部只用标准库

快速开始

# 1. 配置密钥(.env 已被 .gitignore 排除,不会入库)
cp .env.example .env        # 编辑 .env 填入 DEEPSEEK_API_KEY
# 或:export DEEPSEEK_API_KEY=sk-...

# 2. 运行(单次执行)
python main.py "写一个快速排序的实现并跑通测试"

# 交互对话模式(持续多轮,像 ChatGPT 一样追问)
python main.py

# 3. 运行单元测试
python -m unittest discover -s tests -v

常用参数:

参数 说明
--workdir DIR / -w 工作目录(沙箱根目录,路径约束在其中)
--max-iter N 最大迭代步数(默认 25)
--plan 先让模型制定执行计划,人工确认后才执行(可多轮修订)
--approve 审查模式:写/改/删文件、执行命令前逐个让你确认(含 diff 预览)
--ask 仅对 shell 命令做人工确认
--save FILE 结束后把会话保存为 JSON
--resume FILE 从已保存的会话继续(追问)

交互对话模式

不带任务参数启动即进入 REPL,会话在内存中持续累积,可像聊天一样多轮追问:

python main.py

交互命令:

命令 作用
/new [名称] 新建会话(缺省自动命名),并切换到它
/list 列出所有会话(* 标记当前)
/switch <名称> 切换到指定会话
/del <名称> 删除指定会话
/save [会话] [文件] 保存全部(或单个)会话,缺省文件 sessions.json
/load <会话> [文件] 从文件加载单个会话
/clear 清空当前会话
/plan 切换计划模式(先出计划并人工确认后执行)
/approve 切换审查模式(改文件/执行命令前逐个确认)
/review 查看/回滚改动(/review git 看 git diff,/review git reset 回滚 checkpoint)
/skills 列出当前可用的技能(来自 .agents/skills/)
/memory 查看长期记忆(项目记忆 MEMORY.md + 用户画像 USER.md)
/usage 显示累计 token 消耗
/help 显示帮助
exit / quit 退出

每个会话拥有独立的对话历史,可互不干扰地并行推进多个任务;/save + /load 支持单会话/全量持久化与跨进程恢复。

工作原理

核心是一个 「思考 → 行动 → 观察」 循环:

[system 提示 + 用户任务]
        │
        ▼
   调用 DeepSeek(带工具 schema)
        │
        ├── 返回 tool_calls ──► 本地沙箱并发执行 ──► 结果回填为 tool 消息 ──┐
        │                                                                   │
        └── 无 tool_calls ──► 任务完成,返回最终回答                          │

每轮请求无状态:完整消息历史在本地内存中重建后发送,不依赖服务端托管的任何状态、代码执行或文件工具。

设计思想

围绕「可插拔、可观测、可恢复」三个目标,做了几处工程化设计:

1. 依赖倒置:可插拔的模型层

llm.py 定义 ChatProvider 协议,Agent 只依赖该协议而非 DeepSeek 的具体实现。换成其它 OpenAI 兼容模型、或在测试里注入 mock,都不必改动 agent 核心。

2. 有预算的上下文管理(三级降级)

模型上下文有限,而工具输出(读文件、命令结果)往往占大头且可重新获取。逼近预算时按优先级压缩(context.py):

  1. 截断最旧的工具输出正文(保留头部,可重新读取);
  2. 摘要较早的对话为一段「记忆」(调用模型压缩);
  3. 兜底丢弃最旧的工具调用轮次。

始终保留 system 提示与最初的用户任务。

3. 韧性错误处理

  • API 层:网络错误 / 5xx / 429 指数退避重试,4xx 直接抛出;
  • 模型层:工具名未知、参数非法、JSON 解析失败 → 以字符串形式回喂给模型,让它自行修正,而不是让循环崩溃;
  • 执行层:命令超时、非零退出码、路径越界,都作为结果返回给模型判断。

4. 用户主权:Codex 式审查模式 + 改动可回滚

--approve(或 REPL 里 /approve)开启审查:任何写文件 / 改文件 / 删文件 / 执行命令都会先展示统一 diff 或完整命令,再问你是否放行:

  • y 允许 → 真正执行;n 拒绝 → 结果回喂给模型,让它调整方案;
  • m 拒绝并留言 → 你的意见作为 tool 结果传回模型,它据此改进;
  • 相同调用有缓存,拒绝过的调用不会重复弹窗打扰。

所有文件改动都会被记录(Workspace.changes),随时用 /review 查看每个操作的统一 diff,并用 /review revert <序号|all> 按需回滚。整个链路:计划审查(事前)→ 工具审批(事中)→ 改动审查与回滚(事后)。

5. Git 集成:自动 checkpoint

进入 REPL 时若工作目录不是已有 git 仓库,会自动 git init(仓库内身份,不污染全局配置),每轮任务有改动就自动提交 checkpoint(commit message 用模型的总结)。/review git 查看最近一个 checkpoint 的 diff——能覆盖 execute_command 的副作用(构建产物、安装的依赖等文件工具追踪不到的部分);/review git reset 一键回滚到上一 checkpoint。若工作目录已是 git 仓库(如你自己的项目),自动进入「只读监视」模式,不做自动提交与破坏性回滚。

6. 上下文有预算、有上限、会校准

  • 三级压缩:截断旧工具输出 → LLM 摘要早期历史 → 兜底丢弃最旧轮次,始终保住 system 与原始任务;
  • 过载保护:单条消息超 60000 字符自动截断、消息总数超上限自动清理最旧轮次;
  • 大结果落盘:超大工具输出完整落盘到 .my_agent_core/results/,上下文只放头部预览 + 路径占位(可重新读取);
  • token 估算动态校准:每轮用 API 返回的真实 usage 反向校准字符估算(usage anchoring);
  • 摘要防注入:LLM 摘要用 <analysis>/<summary> 双标签,提取时只取 <summary> 正文,防止历史中的恶意内容伪造摘要;
  • 用户输入与模型输出各有长度上限,从源头防止上下文失控。

7. 长期记忆(跨会话)

agent 有 memory 工具 + 工作目录 .my_agent_core/memory/:可把项目约定、踩坑记录、用户偏好写入长期记忆,下次会话仍生效。两类记忆分文件存储:MEMORY.md(项目事实,上限 2200 字符)与 USER.md(用户偏好画像,上限 1375 字符),memory 工具用 target=memories|user 选择写入目标。关键设计是冻结快照——记忆在启动时注入 system prompt 后本会话全程静止,既不污染当前上下文也保护前缀缓存;写操作只落盘、不动快照,新记忆下个会话生效。

8. 声明式技能(Skills)

技能是 .agents/skills/<技能名>/SKILL.md 组成的声明式扩展:frontmatter 提供 name/description,正文是按步骤的指令。启动时 agent 只把轻量技能清单(名称+描述)注入 system prompt,零正文 token 开销;当任务与技能匹配时,agent 调用 invoke_skill(name) 按需加载完整指令再严格照做——用纯文本声明能力,无需改一行代码。可用 /skills 查看、/memory 查看记忆。

9. 并发工具执行:因果时序保护

模型在同一次响应里给出多个工具调用时,仅当全部为只读工具才并发;批内含任何写操作则严格按模型输出顺序串行——避免 read 先于 write 读到旧数据(因果倒置)。审查/确认模式下自动退回顺序。

10. 计划先行:人工审核后再执行

--plan 让模型先产出分步计划,然后暂停等你确认:y 按计划执行、m 给修改意见重拟、n 重新制定、c 取消。可多轮往返直到你满意,计划获批后才进入执行循环,避免模型带着未经确认的计划贸然动手。

11. 可观测:流式输出 + Markdown 终端渲染

推理文本流式打印;模型输出是 Markdown,终端不会渲染——项目内实现了一个纯标准库的 Markdown → ANSI 渲染器(markdown.py,按行缓冲避免流式切碎标记),支持标题、加粗、行内代码、代码块、列表;工具调用与结果可视化,结尾统计 token 消耗。

目录结构

main.py          命令行入口(单次执行 + 交互 REPL + 多会话 + 审查模式)
agent.py         主循环 + 终止条件 + 并发执行 + 计划/摘要编排 + 审批回喂
llm.py           ChatProvider 协议 + DeepSeek 客户端(标准库 HTTP + SSE 流式解析)
context.py       对话历史、token 估算、三级上下文压缩、过载保护
session.py       会话管理:多会话创建/切换/删除/持久化(含校准系数恢复)
gitwrap.py       Git 集成:自动 init + 每轮任务 checkpoint + git diff/回滚
memory.py        长期记忆:MEMORY.md + USER.md + 冻结快照注入(跨会话)
skills.py        声明式技能:.agents/skills/ 发现、frontmatter 解析、清单注入
markdown.py      轻量 Markdown → ANSI 终端渲染器(纯标准库,流式按行缓冲)
parser.py        模型输出解析(工具参数 JSON 容错、content 兜底识别)
config.py        配置(环境变量 / .env)
tools/
  __init__.py    工具注册表 + 工作目录沙箱(越界防护、diff 预览、审批)
  errors.py      RequestDenied 异常
  files.py       read_file / write_file / edit_file / list_files / delete_file
  shell.py       execute_command(subprocess + 超时 + 确认)
  search.py      search_files(文件内容 grep)
  memory.py      memory 工具(target 选择 MEMORY.md / USER.md)
  skills.py      invoke_skill 工具(按需加载技能正文)
tests/           核心逻辑的单元测试(标准库 unittest)

关键设计对照题目要求

题目要求 实现位置与做法
对话历史与上下文管理 context.py:token 估算 + 三级压缩
工具定义与本地执行 tools/:JSON Schema + 本地 executor,沙箱约束
模型输出解析 llm.py 流式增量拼接 + parser.py JSON 容错
循环终止条件 agent.py:无工具调用 → 完成;达最大步数 → 收尾;异常 → 退出
错误处理 API 退避重试;工具错误回喂自愈;命令超时/截断/越界防护

安全边界

  • 所有文件路径经 Workspace.resolve 归一化并做越界防护,约束在 --workdir 内;
  • 命令在沙箱目录下执行,带超时(默认 60s)与输出截断(默认 12000 字符);
  • 密钥只从环境变量或 .env 读取,绝不进入代码、仓库或日志。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages