大模型应用工程化实战:用Harness构建自我进化的学习助手 如果你正打算用大模型做一个真正能用的“学习助手”你会发现一个很典型的失控过程一开始只是“提示词 调 API”跑通几个 demo 之后开始加知识库、加对话历史、加用户画像然后系统变成一锅粥——上下文越攒越长导致超限、模型回答时知识库内容混杂、用户反复答错同类题目但助手毫无反应。这不是模型能力不够而是你缺了一个负责“驾驭”模型的工程层。这篇文章围绕 2026 年 AI 应用开发中最值得关注的一句话展开写提示词的时代正在过去做 Harness 的时代正在到来。我会用一个“自我进化的 AI 学习助手”开发案例把 Harness驾驭工程、自我进化 Agent、上下文工程这三个关键词串起来讲清楚架构怎么设计、代码怎么写、坑在哪里以及真正能让系统越用越聪明的机制是什么。建议先收藏再慢慢看。全文偏工程实践适合正在做 AI 应用、Agent 开发或学习辅助工具的开发者。1. 这篇文章真正要解决的问题先说结论大多数 AI 项目不是死于模型不够强而是死于缺少 Harness 层。什么是 Harness英文原意是“马具、挽具”在 AI 工程领域你可以把它理解为控制模型、工具、记忆、上下文这几样东西相互协作的“控制器”。它决定了大模型在一个应用里能以多稳定的方式完成任务。把这个问题放回“学习助手”场景它的具体表现有三个上下文管理失控。用户和助手聊了 30 轮之后光历史消息可能就超过模型窗口的一半。如果不做裁剪、摘要、重构模型要么报错要么“忘记”最开始的指令。知识库和对话互相污染。用户问的是“帮我解释一下梯度下降”检索出来的课件片段、历史聊天记录、用户上次的错误答案全部混在一起。模型不知道该以哪个为准回答质量直线下降。系统没有成长能力。用户答错了一道题助手当时纠正了但第二天再答同类题它完全不记得。没有反馈闭环谈不上“自我进化”。这篇文章要解决的就是这三个问题。我会用一套完整的学习助手工程案例展示怎么通过 Harness 层统一管理上下文装配、Agent 决策、记忆更新和反思机制让系统具备基础的自进化能力。你读完能收获三样东西一是一套可以直接参考的项目结构二是 Harness、Agent、上下文工程三个概念如何落到代码三是一份避坑清单。2. 先理解三个关键词Harness、自我进化 Agent、上下文工程2.1 HarnessAI 应用的“中控台”如果你只把大模型当成一个“函数调用”那确实不需要 Harness。但真实应用里模型要访问知识库、要读写记忆、要调用工具、要处理多轮对话这些环节如果全部写在业务代码里最后一定是混乱的。Harness 层做的事情是把这些能力“编排”起来注册和管理工具。统一组装备注system prompt 知识 历史 用户输入。调用大模型并解析输出。触发记忆更新和反思。类比一下模型是发动机知识库是油箱记忆是仪表盘Harness 就是那个把方向、油门、刹车、仪表全部连接起来的驾驶系统。没有它你只是抱着一个发动机在跑。2.2 自我进化 Agent是一种工程机制不是玄学“自我进化”这个词听起来很科幻但在工程上它指的是一个闭环** Agent 通过反馈数据持续调整自己的知识结构和回答策略。**常见的实现方式有反思机制ReflectionAgent 在完成一次回答或一轮任务后用一次额外的模型调用分析自己的回答是否有遗漏、是否有错误、是否有更好的讲解路径。记忆更新Memory Update根据用户的答题结果、纠错行为、搜索历史更新用户画像和知识点掌握度。经验沉淀Experience Pool把成功的解答过程和有效策略抽象成“经验卡”后续遇到相似问题时优先参考。学习助手非常适合做自我进化因为它天然有“测试—反馈—纠正—再测试”的场景。2.3 上下文工程决定模型能发挥多少实力如果说 Harness 是框架上下文工程就是框架里最核心的细节。同一个模型上下文中放什么、放多少、怎么排直接决定回答质量。上下文工程需要处理的问题包括哪些历史信息应该保留哪些应该丢弃。检索出来的知识片段如何与用户问题拼接。系统提示词应该写多长、放哪些变量。当前上下文预计消耗多少 token要给回答留多少空间。以前我们常说“提示词工程”但提示词只是上下文工程的一部分。当你开始做 Agent 和 RAG上下文就不只是“一段写在代码里的 prompt”而是一个动态组装的过程。2.4 三者的关系关键词解决什么问题工程落点Harness模型、工具、记忆、上下文的整体编排控制层架构设计自我进化 Agent系统越用越准确、越用越懂用户反馈闭环与反思机制上下文工程模型窗口内的信息质量与效率上下文装配与压缩策略关系很好记上下文工程是 Harness 的左膀自我进化是 Harness 的右臂。3. 学习助手的需求分析从场景到功能再到架构3.1 核心用户场景我们定义的目标用户是“正在学习某一门新技术的开发者”例如正在学 Python 或机器学习基础。典型场景有三个答疑用户遇到不懂的概念直接提问。助手需要基于知识库和用户的历史学习记录作答。出题用户希望检验自己掌握程度助手生成习题并判断答案对错。学习规划用户告诉助手自己的目标和时间助手生成学习计划并在后续对话中跟踪进度。3.2 功能拆解功能说明关键依赖答疑结合 RAG 检索和对话历史回答知识库、上下文工程出题测评按知识点出题自动判题知识图谱、题库模板学习规划动态生成计划按进度调整用户画像、长期记忆进度跟踪记录知识点掌握度形成可视化概览记忆存储、定期反思3.3 技术架构选择技术栈使用 Python FastAPI Redis 向量数据库可使用 Chroma 或 Qdrant根据团队熟悉度选择 大模型 API示例中使用 DeepSeek API 作为模型后端实际可替换为其他兼容接口。架构分层如下API 层对外提供 HTTP 接口接收用户请求。Harness 层核心编排负责上下文装配、工具调用、模型交互、记忆更新。Agent 层业务决策判断用户请求属于答疑、出题还是规划。Memory 层用户画像、短期对话历史、长期知识点掌握度、反思记录。RAG 层对学习资料做切片、向量化、检索。这样的分层带来了一个直接好处业务逻辑不会散落在模型调用代码里后续换模型、加工具、调上下文策略都能集中在 Harness 层完成。4. 环境准备与前置条件在写代码之前先准备环境。版本信息请以实际安装为准本文重点演示通用思路。4.1 基础环境Python 3.10 或更高版本。Redis 6.0 以上用于存储近期对话和用户状态。一个兼容 OpenAI 风格接口的大模型 API 服务。示例中使用 DeepSeek API你可以在环境变量中配置DEEPSEEK_API_KEY也可以换成其他提供商。向量数据库先用轻量的 Chroma 跑通流程生产环境再切换到 Qdrant 或 Milvus。4.2 项目目录结构ai-study-mate/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── harness.py # Harness 核心类 │ ├── agent.py # 学习 Agent │ ├── context_assembler.py # 上下文装配 │ ├── memory.py # 记忆存储 │ └── rag.py # 知识库检索 ├── config/ │ └── application.yaml # 配置文件 ├── data/ │ └── course_materials/ # 课程资料 ├── tests/ └── requirements.txt4.3 安装依赖创建一个requirements.txtfastapi0.104 uvicorn0.24 redis5.0 openai1.30 chromadb0.4 pyyaml6.0 pydantic2.0安装命令pip install -r requirements.txt如果没有设置虚拟环境建议先创建python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate安装完成后可以用python -c import fastapi, openai, redis; print(ok)验证依赖是否正常。5. 核心流程拆解Harness 如何工作5.1 一次请求的完整链路以用户提问“什么是反向传播”为例API 层收到用户请求带上user_id。Harness 层从 Memory 加载用户画像、短期对话历史、知识点掌握度。RAG 层从课程资料中检索“反向传播”相关片段。上下文装配器生成动态 system prompt并组装 messages。调用大模型得到回答。回答写入短期记忆。触发异步反思总结本次回答中暴露的知识点更新用户画像。这个链路中最容易出错的是第 2 步和第 4 步也就是上下文装配。5.2 上下文装配策略一个常见误区是把系统 prompt、检索文档、历史记录、用户输入全部简单拼成一个 list。人眼看着没问题模型实际处理时会出现主次不分的问题。更稳妥的策略是给每个部分分配预算。假设模型上下文上限 8000 token上下文部分预算说明系统提示词10%角色、任务、输出规范检索文档30%最多 3 篇每篇截断历史对话20%最近 6 轮超出则摘要用户输入10%当前问题预留输出30%保证回答不被截断这个比例不是固定的但它能防止“历史对话霸屏”导致知识库信息被忽略。5.3 自我进化的触发点自我进化不是每时每刻都在跑而是在关键节点触发回答后反思每次答疑后判断是否需要反思。可以用固定间隔或随机采样。做题后更新用户提交习题答案后按知识点更新掌握度。每周复盘汇总一周对话提炼薄弱点和学习偏好更新长期画像。反思机制要注意成本每一次反思都是一次模型调用。所以示例中使用reflection_interval控制频率避免每个请求都触发反思。6. 完整示例代码实现下面进入核心代码部分。我会按文件给出可运行的实现并解释关键逻辑。6.1 Harness 核心类代码路径app/harness.py# 文件路径app/harness.py from __future__ import annotations import json import time import uuid from dataclasses import dataclass, field from typing import Any, Callable, Dict, List, Optional from openai import OpenAI dataclass class HarnessConfig: model_name: str deepseek-chat base_url: str https://api.deepseek.com max_context_tokens: int 8000 temperature: float 0.3 reflection_interval: int 3 # 每 N 次回答触发一次反思 max_iterations: int 3 # Agent 单次任务最大迭代次数 class Harness: def __init__(self, config: HarnessConfig, api_key: str): self.config config self.client OpenAI(api_keyapi_key, base_urlconfig.base_url) self.tools: Dict[str, Callable] {} self.memory None self.rag None self.request_counter 0 def register_tool(self, name: str, func: Callable) - None: 注册工具供 Agent 在迭代中调用。 self.tools[name] func def bind_memory_and_rag(self, memory, rag) - None: 绑定记忆存储和知识库检索组件。 self.memory memory self.rag rag def call_llm(self, messages: List[Dict[str, str]]) - str: 调用大模型返回文本结果。 resp self.client.chat.completions.create( modelself.config.model_name, messagesmessages, temperatureself.config.temperature, ) return resp.choices[0].message.content def run( self, user_id: str, user_input: str, system_prompt: str, recent_messages: Optional[List[Dict[str, str]]] None, ) - str: 主入口装配上下文、调用模型、更新短期记忆。 # 1. 检索知识库 docs self.rag.search(user_input, top_k3) if self.rag else [] # 2. 组装上下文 messages ContextAssembler.assemble( system_promptsystem_prompt, user_inputuser_input, docsdocs, recent_messagesrecent_messages, ) # 3. 调用模型 answer self.call_llm(messages) # 4. 更新计数器决定是否触发反思 self.request_counter 1 return answer这段代码的核心是run方法。它把“检索、装配、调用、计数”集中在一个流程里业务方不需要知道上下文怎么组装。后续如果要在调用前增加检索重排、或者调用后增加输出校验都只需要改这一处。6.2 上下文装配器代码路径app/context_assembler.py# 文件路径app/context_assembler.py from typing import Dict, List class ContextAssembler: staticmethod def assemble( system_prompt: str, user_input: str, docs: List[str], recent_messages: List[Dict[str, str]], max_docs: int 3, ) - List[Dict[str, str]]: 把系统提示、检索文档、历史消息、当前输入组装成 messages。 注意这里的组装顺序是从“角色优先级”出发而不是简单拼接。 # 1. 系统提示 messages: List[Dict[str, str]] [ {role: system, content: system_prompt} ] # 2. 最近对话历史保留最近 6 轮 if recent_messages: messages.extend(recent_messages[-6:]) # 3. 知识库文档内容截断文档数量防止上下文膨胀 doc_content if docs: docs docs[:max_docs] doc_content \n\n.join( [f[资料{i1}] {doc} for i, doc in enumerate(docs)] ) # 4. 当前用户问题 if doc_content: user_content ( 以下是相关的课程资料请结合资料回答 如果资料不足以回答请如实说明\n\n f{doc_content}\n\n问题{user_input} ) else: user_content f问题{user_input} messages.append({role: user, content: user_content}) return messages这里的核心原则是参考资料的优先级高于裸问题但没有资料时要让模型有“说不知道”的空间。6.3 记忆存储代码路径app/memory.py# 文件路径app/memory.py import json from typing import Dict, List class MemoryStore: 简化的记忆存储实现。 生产环境可以替换为 Redis Hash 或专门的记忆服务。 def __init__(self): self._conversation: Dict[str, List[Dict]] {} self._profile: Dict[str, Dict] {} def get_recent_messages(self, user_id: str) - List[Dict]: return self._conversation.get(user_id, []) def save_message_pair(self, user_id: str, user_input: str, answer: str) - None: session self._conversation.setdefault(user_id, []) session.append({role: user, content: user_input}) session.append({role: assistant, content: answer}) # 只保留最近 20 条 if len(session) 20: session session[-20:] self._conversation[user_id] session def get_profile(self, user_id: str) - Dict: return self._profile.setdefault( user_id, {knowledge_level: {}, weak_points: [], preferences: {}}, ) def update_knowledge_level( self, user_id: str, topic: str, score: float, correct: bool ) - None: profile self.get_profile(user_id) level profile[knowledge_level] current level.get(topic, {mastery: 0.0, attempts: 0, correct: 0}) current[attempts] 1 if correct: current[correct] 1 # 基础掌握度正确率 * 0.7 尝试次数惩罚因子 current[mastery] round(current[correct] / current[attempts] * 0.7, 2) level[topic] current def save_reflection(self, user_id: str, insight: str) - None: profile self.get_profile(user_id) profile.setdefault(reflections, []).append(insight)这个实现是内存版重启会丢失。生产环境建议用 Redis Hash 或数据库表存储但逻辑可以完全复用。6.4 自我进化 Agent代码路径app/agent.py# 文件路径app/agent.py import json from typing import Dict from app.context_assembler import ContextAssembler from app.harness import Harness class LearningAgent: def __init__(self, harness: Harness, memory): self.harness harness self.memory memory def answer_question(self, user_id: str, question: str) - str: profile self.memory.get_profile(user_id) system_prompt self._build_system_prompt(profile) recent self.memory.get_recent_messages(user_id) answer self.harness.run( user_iduser_id, user_inputquestion, system_promptsystem_prompt, recent_messagesrecent, ) self.memory.save_message_pair(user_id, question, answer) # 触发反思 if self.harness.request_counter % self.harness.config.reflection_interval 0: self._reflect(user_id, question, answer) return answer def submit_quiz(self, user_id: str, topic: str, is_correct: bool) - str: 提交一道题的结果更新该知识点的掌握度。 profile self.memory.get_profile(user_id) old_level profile[knowledge_level].get(topic, {}).get(mastery, 0.0) self.memory.update_knowledge_level( user_iduser_id, topictopic, score1.0 if is_correct else 0.0, correctis_correct, ) new_profile self.memory.get_profile(user_id) new_level new_profile[knowledge_level][topic][mastery] if new_level old_level: return f知识点「{topic}」掌握度提升至 {new_level:.2f} return f知识点「{topic}」仍需加强当前掌握度 {new_level:.2f} def _reflect(self, user_id: str, question: str, answer: str) - None: 反思机制让模型回顾刚才的回答提取可改进点。 注意反思内容不会直接返回给用户而是写入长期画像。 prompt ( 请回顾你刚才对用户问题的回答从讲解清晰度、知识准确性、 是否补充示例、是否给出下一步建议四个维度自我评估。 输出 JSON字段为score(int), weak_points(list), suggestion(str)。 ) try: insight self.harness.call_llm( [ {role: system, content: 你是一个严格的自我评估器。}, {role: user, content: f用户问题{question}\n你的回答{answer}\n{prompt}}, ] ) self.memory.save_reflection(user_id, insight) except Exception as e: print(f[reflect error] {e}) def _build_system_prompt(self, profile: Dict) - str: knowledge_info json.dumps(profile.get(knowledge_level, {}), ensure_asciiFalse) weak_points 、.join(profile.get(weak_points, [])[:5]) or 暂无 return ( 你是一名耐心、严谨的编程学习助手。 回答时遵循以下原则\n 1. 先给出结论再解释原因\n 2. 如果用户的知识点掌握度较低优先使用类比和示例\n 3. 如果检索资料不足以回答明确告诉用户\n f4. 用户当前薄弱点是{weak_points}\n f5. 用户已掌握的知识点概况{knowledge_info}\n 最后提出一个帮助用户巩固知识的小问题。 )6.5 FastAPI 接口代码路径app/main.py# 文件路径app/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from app.agent import LearningAgent from app.harness import Harness, HarnessConfig from app.memory import MemoryStore app FastAPI(titleAIStudyMate API, version0.1.0) class AskRequest(BaseModel): user_id: str question: str class QuizRequest(BaseModel): user_id: str topic: str is_correct: bool # 全局组件生产环境可封装在依赖注入容器中 memory_store MemoryStore() harness Harness( configHarnessConfig(), api_keyYOUR_API_KEY, # 强烈建议改为从环境变量读取 ) agent LearningAgent(harnessharness, memorymemory_store) app.post(/api/ask) def ask(req: AskRequest): try: answer agent.answer_question(req.user_id, req.question) return {user_id: req.user_id, answer: answer} except Exception as e: raise HTTPException(status_code500, detailstr(e)) app.post(/api/quiz/submit) def submit_quiz(req: QuizRequest): try: result agent.submit_quiz(req.user_id, req.topic, req.is_correct) return {user_id: req.user_id, message: result} except Exception as e: raise HTTPException(status_code500, detailstr(e))这里要特别提醒不要把 API Key 硬编码在代码里。实际开发时使用环境变量或密钥管理服务export DEEPSEEK_API_KEY你的密钥然后在代码中改为import os api_key os.getenv(DEEPSEEK_API_KEY)6.6 配置文件示例代码路径config/application.yamlserver: port: 8080 ai: model: deepseek-chat base_url: https://api.deepseek.com max_context_tokens: 8000 temperature: 0.3 reflection_interval: 3 memory: redis_url: redis://localhost:6379/0 recent_limit: 20 rag: type: chroma embedding_model: text-embedding top_k: 3 chunk_size: 512 chunk_overlap: 64配置文件可以让团队在不改代码的情况下调整上下文预算、反思频率和检索策略这是 Harness 层的一个重要优势。7. 运行结果与效果验证7.1 启动服务在项目根目录执行uvicorn app.main:app --reload --port 8080看到类似输出说明启动成功INFO: Uvicorn running on http://127.0.0.1:80807.2 调用答疑接口curl -X POST http://127.0.0.1:8080/api/ask \ -H Content-Type: application/json \ -d {user_id: user01, question: 什么是反向传播}预期返回结构{ user_id: user01, answer: 反向传播是一种用于训练神经网络的核心算法...此处为模型实际回答 }7.3 模拟一次学习反馈curl -X POST http://127.0.0.1:8080/api/quiz/submit \ -H Content-Type: application/json \ -d {user_id: user01, topic: 反向传播, is_correct: true}预期返回{ user_id: user01, message: 知识点「反向传播」掌握度提升至 0.70 }7.4 验证要点第一次提问后短期记忆中应该保存了问答对。提交多次习题结果后memory_store.get_profile(user01)中的knowledge_level应持续变化。连续提问reflection_interval的倍数次数后控制台可能打印反思相关日志但正常用户无感。如果持续提问同一个问题第二次回答应该参考到第一次的历史上下文。8. 常见问题与排查思路问题现象可能原因排查方式解决方案模型返回内容被截断上下文预算分配不合理输出预留不足查看模型返回是否有 finish_reason 为 length降低历史对话轮数提升输出预留比例检索到的文档与问题无关分块策略不合适或 top_k 过大打印检索返回的文档内容减小 chunk_size增加相关性重排Agent 重复回答同一问题缺少最大迭代限制查看 Harness 日志中的循环记录在call_llm外层增加max_iterations控制记忆没有生效内存版数据丢失或 Redis 未启动检查memory_store内容确认 Redis 连接换用 Redis 存储确认后台服务正常反思机制频繁调用API 费用过高reflection_interval设置过小查看请求计数与费用账单调大reflection_interval配合低峰期批量反思模型回答太笼统system prompt 没有针对用户画像做定制检查_build_system_prompt生成的 prompt把薄弱点、知识概况更紧凑地放入 prompt环境依赖安装失败Python 版本或依赖冲突查看 pip 错误日志使用虚拟环境统一 Python 3.109. 最佳实践与工程建议9.1 把上下文预算写进设计文档不要等到上下文超限才开始想怎么裁剪。在项目初期就明确每个模块的 token 预算Harness 层才能做到“有据可裁”。我把预算写进配置文件的目的是让运维和产品也能参与调整。9.2 反思机制要控制成本避免“为了反思而反思”很多团队一听到“自我进化”就高频触发反思。实际上反思是一次额外模型调用成本接近一次正常回答。更合理的做法是按固定间隔抽样反思示例中的reflection_interval。在用户反馈“回答没用”时触发强制反思。在题目错误率超过阈值时触发按知识点反思。9.3 学习数据脱敏与最小权限学习助手会记录用户知识薄弱点、答题记录、对话内容。这些都是敏感数据。上线前要明确用户明示同意后才记录长期画像。短期内只保留必要数据示例中保留 20 条。API Key 只保存在服务端环境变量或密钥管理服务不进入代码仓库。9.4 可观测性每个请求都要有 trace在生产环境最重要的事是“出问题能查”。建议在 Harness 层为每次请求生成一个trace_id记录上下文 messages 的每个部分 token 估算值。检索文档的引用列表。模型返回的 finish_reason。反思是否触发是否成功。没有 trace 的 Agent 项目一旦线上回答异常排查会极其痛苦。9.5 渐进式上线先用离线数据验证进化效果“自我进化”是否真的有效可以用离线数据集检验准备一批历史问答对跑一遍旧系统的回答再跑一遍加入反思与记忆更新后的回答对比正确率或用户满意度。不要一上线就让新机制直接接管线上流量。9.6 适合继续深入的方向如果你看完本文希望继续深入推荐按这个顺序学习重新阅读 Harness 层代码尝试加入一个“抽卡工具”或“复习提醒工具”。把内存版MemoryStore替换成 Redis理解短期记忆和长期画像的持久化问题。给 RAG 部分加入文本切片和 Embedding 流程让知识库真正可扩展。尝试在反思机制中引入结构化输出例如让模型输出 JSON 格式的改进指令。做完这些你的学习助手就不再是一个“调 API 的聊天机器人”而是一个有状态、有反馈、可持续迭代的 AI 应用了。订阅我的专栏持续关注大模型工程化、Agent 开发与上下文工程实战内容。