
从聊天框到改代码:手写一个 Coding Harness
同一个大模型,套在聊天框里只能给建议,套进一个 harness 就能读、改、跑你的仓库。本文用一个能跑通的最小实现 cookllm-harness,拆解这层 harness 的六个组件,并记录用 DeepSeek V4 落地时踩到的坑。
Companion Code你在网页聊天框里问模型“帮我把这个函数的 bug 修了”,它会给你一段看起来很对的代码,但它从没见过你的仓库,不知道你用的是哪个版本的依赖,也没法真的把改动写进文件、跑一遍测试确认。
而像 Claude Code、Cursor 这类工具,背后用的往往是同一个模型,却能在你的项目里读文件、改代码、跑命令、看报错、再改。
差别不在模型,在模型外面那层东西。这层东西有个名字,叫 coding harness。
这篇文章不讲“怎么调 API 让模型写代码”,而是拆开这层 harness,看清它到底由哪些零件组成。我们会用一个我自己写的、能真机跑通的最小实现 cookllm-harness 当作骨架,每讲一个零件就指向一段真实代码。后端用 DeepSeek V4,所以最后还会记录几个只有真正落地才会踩到的坑。
一个会写代码的模型,为什么改不动你的仓库
把大模型想象成一个只会对着菜谱念字的厨师。你给它一段文字(菜谱),它回你一段文字(念出来的步骤)。它的全部能力就是“文本进、文本出”。
这个厨师可能厨艺极高,但你把他空降到你家厨房,他立刻抓瞎:
- 他不知道你的冰箱里有什么(看不到仓库现状)。
- 他没有刀和锅(没有能动手的工具)。
- 他记不住上一道菜放了多少盐(没有跨步骤的记忆)。
- 他不能尝一口再调整(拿不到执行结果的反馈)。
所谓 coding harness,就是给这个厨师配齐厨房:把冰箱里的食材列给他看,给他刀具和灶台,给他一个记事本,并且每做一步都让他尝一口、看一眼结果。模型本身没变,变的是它周围的这套基础设施。
四个被混用的词
聊这个话题时,四个词经常被混着用,先各自归位。
- 模型(Model):那个只会文本进文本出的厨师本人。
deepseek-v4-flash是一个模型。 - 推理(Inference):让厨师念一次菜谱的动作,也就是一次 API 调用。一次推理只产出一段文本。
- Agent:让厨师反复念、并且根据上一步结果决定下一步的循环。它把“一次推理”变成“读文件 → 想 → 改文件 → 跑测试 → 看报错 → 再改”的多步过程。
- Harness:支撑这个循环的整套厨房设施,包括工具、权限、上下文管理、记忆、子任务调度。Agent 是循环逻辑,harness 是让循环能安全跑起来的地基。
Four terms, one nesting
They are not four parallel things — each one sits inside the next.
后面我们要拆的,主要就是 harness 这层地基。
六大组件总览
一个能用的 coding harness,大致由六个组件组成。下面先列出来,每个一句话,后面逐个对着真实代码拆开。
| # | 组件 | 一句话职责 |
|---|---|---|
| 1 | 仓库现场(Live repo context) | 让模型每次开口前就知道自己站在哪个仓库、哪个分支、改了什么 |
| 2 | 提示词形状与缓存复用 | 把不变的部分放在前面,让 API 缓存命中,省钱又省延迟 |
| 3 | 结构化工具、校验与权限 | 模型不能乱敲命令,只能从固定工具里选,且每次调用都过一道闸 |
| 4 | 上下文削减 | 工具输出会撑爆上下文窗口,必须主动裁剪 |
| 5 | 转录、记忆与续跑 | 完整对话存盘可续跑,外加一份精炼的工作记忆 |
| 6 | 有界委派 | 主 agent 能派一个受限的子 agent 去查支线任务,且不会无限递归 |
cookllm-harness:一个能跑的最小实现
为了让这六个组件不停留在概念,我把它们各自落进一个独立模块,组成一个能真机跑通的小项目 cookllm-harness。它故意写得很小,目的是好读:
模块和组件的对应关系:
| 组件 | 模块 |
|---|---|
| 1 仓库现场 | harness/workspace.py |
| 2 提示词形状与缓存 | harness/agent.py(系统提示)+ DeepSeek 前缀缓存 |
| 3 工具、校验与权限 | harness/tools.py |
| 4 上下文削减 | harness/context.py |
| 5 转录、记忆与续跑 | harness/session.py |
| 6 有界委派 | harness/agent.py(delegate 工具) |
跑起来是这样的:
export DEEPSEEK_API_KEY=sk-...
python cli.py "列出所有 python 文件,并说明这个仓库是做什么的"模型不会凭空回答,而是先调 list_files 看目录,再 read_file 读关键文件,最后才给出结论。下面我们就顺着这条调用链,把六个组件逐个拆开。
Log in to continue reading
This is premium content. Please log in to access the full article.