DeepSeek Agent Harness 2026终极指南 - 第11章第52节 文件树注入:让Agent看见项目全貌
第51节解决了"历史太长",但还有个问题——Agent 不知道项目长什么样。你让它"改一下用户模块的代码",它得先猜文件在哪、有哪些文件、依赖是什么。这节做文件树注入:把项目结构树、README、pyproject、git 状态一起塞进上下文,让 Agent 一启动就"看见"项目全貌,不用瞎猜、不用反复 grep。
本文导航
- Agent 为什么需要"看见"项目
- 项目结构树生成与token控制
- 重要文件自动注入
- git状态与最近提交注入
- 完整实现:context_inject.py
- 实测:Agent 一启动就懂项目
- 小结
Agent 为什么需要"看见"项目
想象两个场景:
场景A:没有文件树。你问 Agent"改一下登录逻辑",Agent 的对话是:
Agent: 让我先找找登录相关的代码。 → grep "login" → 找到 auth.py、login.py、user.py 三个文件(但不知道哪个是主入口 → 还得再读 README、读 pyproject 确定项目结构 → 来回好几轮,才搞清楚项目长什么样场景B:有文件树注入。你问同样的问题,Agent 一启动就看到:
项目结构: deep_pilot/ ├── config.py # 配置 ├── client.py # DeepSeek 客户端 ├── auth.py # 登录认证逻辑 ├── ...Agent: 我看到了,auth.py 是登录认证模块,直接改它就行。环境感知是 Agent 效率的关键。注入项目结构能让 Agent 少做很多无用功。
项目结构树生成与token控制
用os.walk或Path.rglob生成目录树:
# deep_pilot/context_inject.py —— 环境注入 v0.6from__future__importannotationsfrompathlibimportPathfromdeep_pilot.loggerimportget_logger logger=get_logger(__name__)# 忽略的目录(生成文件树时跳过)IGNORE_DIRS={".git","node_modules",".venv","__pycache__","dist","build",".pytest_cache",".tox"}# 忽略的文件IGNORE_FILES={".pyc",".pyo",".so",".dll",".exe"}defgenerate_tree(root:Path,max_depth:int=3,max_files:int=200)->str:""" 生成项目结构树。 max_depth: 最大目录深度 max_files: 最多列出的文件数 """root=Path(root).resolve()lines=[]file_count=0defwalk(dir_path:Path,prefix:str,depth:int):nonlocalfile_countifdepth>max_depth:lines.append(f"{prefix}...(深度超限,已省略)")returnentries=sorted(dir_path.iterdir(),key=lambdap:(p.is_file(),p.name))forentryinentries:# 跳过忽略项ifentry.nameinIGNORE_DIRS:continueifentry.is_file()andentry.suffixinIGNORE_FILES:continueiffile_count>=max_files:lines.append(f"{prefix}...(文件数超限,已省略)")returnifentry.is_dir():lines.append(f"{prefix}├──{entry.name}/")walk(entry,prefix+"│ ",depth+1)else:lines.append(f"{prefix}├──{entry.name}")file_count+=1lines.append(f"{root.name}/")walk(root,"",1)return"\n".join(lines)token 控制的三板斧:
- max_depth:限制目录深度,太深的目录不展开
- max_files:限制文件数量,超过就省略
- 忽略目录:
.git、node_modules等大目录直接跳过
一个典型的中型项目,生成的文件树约 800-1500 token,可接受。
重要文件自动注入
除了结构树,几个"关键文件"值得完整注入——它们是理解项目的钥匙:
definject_important_files(root:Path)->str:"""注入重要文件内容(README/pyproject等)"""important_files=["README.md","pyproject.toml",".env.example",]parts=[]forfnameinimportant_files:fpath=root/fnameiffpath.exists():content=fpath.read_text(encoding="utf-8",errors="ignore")# 限制每个文件最多注入 1000 字符iflen(content)>1000:content=content[:1000]+"\n...[已截断]"parts.append(f"###{fname}\n```\n{content}\n```")return"\n\n".join(parts)为什么是这几个文件?
- README.md:项目是干嘛的、怎么用,一目了然
- pyproject.toml:依赖、版本、构建配置,理解技术栈
- .env.example:需要哪些环境变量(不含真实密钥)
git状态与最近提交注入
git 状态告诉 Agent"最近在改什么",避免重复劳动:
importsubprocessdefinject_git_status(root:Path)->str:"""注入 git 状态和最近提交"""parts=[]# git statustry:status=subprocess.run(["git","status","--short"],cwd=root,capture_output=True,text=True,timeout=5,)ifstatus.returncode==0andstatus.stdout.strip():parts.append(f"### Git 状态(未提交的改动)\n```\n{status.stdout.strip()}\n```")exceptException:pass# 最近提交try:log=subprocess.run(["git","log","--oneline","-5"],cwd=root,capture_output=True,text=True,timeout=5,)iflog.returncode==0andlog.stdout.strip():parts.append(f"### 最近提交\n```\n{log.stdout.strip()}\n```")exceptException:passreturn"\n\n".join(parts)git 状态的价值:如果 Agent 看到"已经有 3 个文件被修改,正在改登录功能",它就会接着这个思路往下做,而不是另起炉灶。
完整实现:context_inject.py
整合成完整模块,拼装成一段"环境上下文":
# deep_pilot/context_inject.py —— 完整版from__future__importannotationsimportsubprocessfrompathlibimportPathfromdeep_pilot.loggerimportget_logger logger=get_logger(__name__)IGNORE_DIRS={".git","node_modules",".venv","__pycache__","dist","build",".pytest_cache",".tox"}IGNORE_FILES={".pyc",".pyo",".so",".dll",".exe"}defgenerate_tree(root:Path,max_depth:int=3,max_files:int=200)->str:root=Path(root).resolve()lines=[]file_count=0defwalk(dir_path:Path,prefix:str,depth:int):nonlocalfile_countifdepth>max_depth:lines.append(f"{prefix}...(深度超限)")returnentries=sorted(dir_path.iterdir(),key=lambdap:(p.is_file(),p.name))forentryinentries:ifentry.nameinIGNORE_DIRS:continueifentry.is_file()andentry.suffixinIGNORE_FILES:continueiffile_count>=max_files:lines.append(f"{prefix}...(文件数超限)")returnifentry.is_dir():lines.append(f"{prefix}├──{entry.name}/")walk(entry,prefix+"│ ",depth+1)else:lines.append(f"{prefix}├──{entry.name}")file_count+=1lines.append(f"{root.name}/")walk(root,"",1)return"\n".join(lines)definject_important_files(root:Path)->str:parts=[]forfnamein["README.md","pyproject.toml",".env.example"]:fpath=root/fnameiffpath.exists():content=fpath.read_text(encoding="utf-8",errors="ignore")iflen(content)>1000:content=content[:1000]+"\n...[已截断]"parts.append(f"###{fname}\n```\n{content}\n```")return"\n\n".join(parts)definject_git_status(root:Path)->str:parts=[]try:status=subprocess.run(["git","status","--short"],cwd=root,capture_output=True,text=True,timeout=5)ifstatus.returncode==0andstatus.stdout.strip():parts.append(f"### Git 状态\n```\n{status.stdout.strip()}\n```")exceptException:passtry:log=subprocess.run(["git","log","--oneline","-5"],cwd=root,capture_output=True,text=True,timeout=5)iflog.returncode==0andlog.stdout.strip():parts.append(f"### 最近提交\n```\n{log.stdout.strip()}\n```")exceptException:passreturn"\n\n".join(parts)defbuild_environment_context(root:Path|str=".")->str:"""构建完整的环境上下文,用于注入 system prompt 或首条消息"""root=Path(root).resolve()sections=[]tree=generate_tree(root)sections.append(f"## 项目结构\n```\n{tree}\n```")important=inject_important_files(root)ifimportant:sections.append(f"## 重要文件\n{important}")git_info=inject_git_status(root)ifgit_info:sections.append(git_info)return"\n\n".join(sections)实测:Agent 一启动就懂项目
uv run python-c" from deep_pilot.context_inject import build_environment_context env_ctx = build_environment_context('.') print(env_ctx[:800]) print('...') print(f'环境上下文总长度: {len(env_ctx)} 字符') "控制台输出(精简):
## 项目结构deep-pilot/
├── deep_pilot/
│ ├──init.py
│ ├── agent_loop.py
│ ├── client.py
│ ├── config.py
│ ├── file_tools.py
│ ├── …
├── tests/
├── pyproject.toml
├── README.md
## 重要文件 ### pyproject.toml[project]
name = “deep-pilot”
dependencies = [“openai”, “pydantic”, …]
... 环境上下文总长度: 2847 字符Agent 一启动就"看见"了项目结构、依赖、README,不用瞎猜。实际使用时,把这段环境上下文注入到 system prompt 或首条 user 消息里:
# agent_loop.py 里env_ctx=build_environment_context(".")messages=[{"role":"system","content":f"你是 DeepPilot 编程助手。\n\n当前项目环境:\n{env_ctx}"},{"role":"user","content":user_query},]小结
- 环境感知是效率关键:注入项目结构让 Agent 少做无用功,一启动就懂项目。
- 文件树生成三控:max_depth 限深度、max_files 限数量、IGNORE_DIRS 跳过无关目录。
- 重要文件注入:README(项目是什么)、pyproject(技术栈)、.env.example(环境变量)。
- git 状态注入:告诉 Agent"最近在改什么",避免重复劳动、接着思路做。
- token 可控:文件树约 800-1500 token,重要文件限 1000 字符,整体几千字符可接受。
- 注入到 system prompt:环境上下文放 system,Agent 全程可见。
- DeepPilot v0.6 文件树注入完成——Agent 从"瞎子摸象"到"一眼看全",效率大幅提升。
下节预告
注入了项目结构,Agent"看见"了。但还有个更根本的问题——系统提示词怎么写。system prompt 是 Agent 的灵魂,决定了它的行为方式。下一节做系统提示词工程:把 DeepPilot 的系统提示词逐段拆解(角色定义/工具规范/安全约束/输出格式),再讲版本管理和回归测试。
如果觉得本文对你有帮助,欢迎点赞、收藏、关注三连!
本系列持续更新中,关注不迷路~