首页
/ Khoj 自定义 Agent 实现指南:从 Admin 创建、权限模型到 API 与知识绑定机制

Khoj 自定义 Agent 实现指南:从 Admin 创建、权限模型到 API 与知识绑定机制

2026-09-05 23:57:04作者:郜逊炳

Agent(代理)是 Khoj 中将"角色设定、专属知识库、可用工具与指定聊天模型"打包成独立对话实体的核心机制。本文以官方文档 Agents 的自托管创建流程为主线,结合 Agent 数据模型AgentAdapters 数据访问层REST API 路由 的源码实现,讲透自建 Khoj 服务中 Agent 的完整配置项、可见性权限规则,以及绑定知识文件后底层如何以原子事务同步向量条目。读完后你可以:在 Django Admin 中创建面向全团队或仅面向个人的 Agent,理解其各字段的落库语义,并能通过 API 以编程方式创建、更新、删除 Agent。

Khoj 官方 Agents 页面完整界面截图,展示 Agent 列表卡片与详情配置

1. Agent 是什么:一套可配置的对话人格

Khoj 文档对 Agent 的定义非常简洁:它允许你在 Khoj 上配置自定义系统提示词(custom system prompts)。服务器管理员(self-hosted 场景下的部署者)可以创建自己的 Agent,并控制其对所有用户是否可见。

在源码中,一个 Agent 远不止一个提示词。Agent 模型 的完整字段构成了它的全部能力面:

字段 类型 默认值 含义
creator ForeignKey → KhojUser None 创建者;为 None 时自动标记为管理员托管
name CharField(200) Agent 显示名称
personality TextField None 自定义系统提示词,即文档中所说的核心配置项
input_tools ArrayField [] 该 Agent 允许的输入侧工具,可取值:general / online / notes / webpage / code(见 InputToolOptions
output_modes ArrayField [] 输出模式,可取值:image / diagram(见 OutputModeOptions
managed_by_admin BooleanField False 是否由管理员托管
chat_model ForeignKey → ChatModel 该 Agent 绑定的聊天模型(必填外键)
slug CharField(200),唯一 自动生成 形如 名称-6位随机数字,由 save() 钩子在首次保存时生成
style_color CharField orange 界面卡片颜色,共 15 种可选色值(blue/green/red 等)
style_icon CharField Lightbulb 界面图标,共 25 种可选图标(Robot/Code/GraduationCap 等)
privacy_level CharField private 可见性:public / private / protected
is_hidden BooleanField False 是否对用户隐藏("隐藏 Agent"用于会话级临时人格)

可以看到,personality 字段承载文档强调的"自定义提示词"职责,而 input_toolsoutput_modeschat_model 和知识文件绑定则让每个 Agent 成为一个能力边界明确的独立助手。

2. 自托管创建 Agent:Django Admin 三步操作

这是 官方文档 给出的核心操作流程,适用于 self-hosted 部署:

  1. 进入管理入口:在浏览器访问你服务器上的 server/admin/database/agent,点击 Add Agent 创建新 Agent;
  2. 配置可见性:将其设置为 public,该 Agent 即对服务器上所有用户可见;若要限制为仅特定用户可用,则不要设置 public 标记,并在 Creator 字段中填入该用户;
  3. 写入人格:把你的自定义系统提示词填入 personality 字段。

这三步之所以成立,背后是对应源码的严格支撑:

  • 管理入口存在的前提是 AgentAdmin 已注册到 Django Admin(@admin.register(Agent)),它提供 id/name 列表展示、按 idname 搜索,以及privacy_level 过滤的侧边栏过滤器——这意味着管理员可以直接按 public/private/protected 三类快速筛查 Agent;
  • "设为 public 即可被所有用户看到"对应数据访问层 get_all_accessible_agents 的查询逻辑:返回的 Agent 集合 = privacy_level == publicmanaged_by_admin == True 的 Agent, creator == 当前用户is_hidden == False 的 Agent。未登录用户只能看到前者。可以推断,Admin 中创建的 Agent 因 creator 为空而自动满足 managed_by_admin(见下一节),所以 public 级别的 Admin Agent 会对全站用户生效;
  • "不设 public + 指定 Creator"对应私有可见性:aget_agent_by_slug 的访问控制表达式为 (privacy_level == public) | (creator == user),即私有 Agent 只有创建者本人能按 slug 取到。

注意一个字段名映射:早期文档措辞中的 public 标记,在现行模型中体现为 privacy_level 字段(取值 public/private/protected)。protected 是第三档——ais_agent_accessible 显示,protected 级别对登录用户判定为可访问,但不会出现在匿名用户的可访问列表中。

3. 模型层关键机制:slug 生成与 managed_by_admin 自动标记

Agent.save() 中有两段值得了解的落库行为:

def save(self, *args, **kwargs):
    is_new = self._state.adding
    if self.creator is None:
        self.managed_by_admin = True
    if is_new and not self.slug:
        random_sequence = "".join(choice("0123456789") for i in range(6))
        slug = f"{self.name.lower().replace(' ', '-')}-{random_sequence}"
        self.slug = slug
    super().save(*args, **kwargs)
  • creatorNone ⇒ 强制 managed_by_admin = True。模型注释明确写道:Creator will only be null when the agents are managed by admin。这正是 Admin 后台创建的 Agent 能进入"全用户可见"白名单的原因;
  • slug 自动派生:首次保存时若未指定 slug,则以 名称小写连字符化 + 6 位随机数字 生成唯一 slug(例如 research-assistant-482913)。slug 是 API 层寻址 Agent 的主键,测试 test_create_default_agent 也验证了默认 Agent 创建后 input_tools == []privacy_level == publicmanaged_by_admin 为真。

4. 默认 Agent:每个 Khoj 实例的"零号 Agent"

除手工创建的 Agent 外,每个部署实例都有一个内建默认 Agent,由 create_default_agent 维护:

  • 名称固定为 Khoj,slug 固定为 khoj(常量 DEFAULT_AGENT_NAME / DEFAULT_AGENT_SLUG);
  • personality 取自 prompts.personality 模板(运行时填充当前日期与星期),聊天模型取服务级默认模型;
  • 创建时会把库中所有 agent=None 的历史会话回填挂到默认 Agent 下,保证会话与 Agent 的关联完整性;
  • 特殊之处:get_agent_chat_model 对默认 Agent 是动态解析模型(跟随用户/服务级默认设置),而其它 Agent 返回其静态绑定的 chat_model

这也解释了 API 返回结构里为什么默认 Agent 会被单列处理:all_agents 将默认 Agent 固定排在列表首位,其余 Agent 按"最近两周会话活跃时间"降序排序,未使用过的随机打散。

5. REST API:以编程方式管理 Agent

自托管场景下,除 Admin 界面外,Khoj 通过 api_agents 路由 提供完整的 Agent CRUD。关键请求体定义在 ModifyAgentBody

class ModifyAgentBody(BaseModel):
    name: str
    persona: str                      # 即 personality,自定义系统提示词
    privacy_level: str
    icon: str
    color: str
    chat_model: str
    files: Optional[List[str]] = []   # 绑定知识文件的文件路径列表
    input_tools: Optional[List[str]] = []
    output_modes: Optional[List[str]] = []
    slug: Optional[str] = None
    is_hidden: Optional[bool] = False

主要端点一览(均来自 api_agents.py):

方法 + 路径 鉴权 说明
GET /agents 可匿名 列出当前用户可访问的全部 Agent(含默认 Agent 置顶、近两周会话排序)
GET /agents/{agent_slug} 可匿名 按 slug 获取只读 Agent 详情
POST /agents 登录 创建 Agent;若 chat_model 免费档不满足订阅权限则降级
PATCH /agents 登录 按 slug 更新 Agent
DELETE /agents/{agent_slug} 登录 删除 Agent(仅创建者可删,见下)
GET /agents/options 可匿名 返回所有 input_tools/output_modes 取值及对应描述文案
POST/PATCH /agents/hidden 登录 创建/更新会话级"隐藏 Agent"(临时人格)

几个源码级的行为细节值得注意:

  • 提示词安全检查POST/PATCH 都会先调用 acheck_if_safe_prompt(body.persona, user, lax=...) 校验 persona 是否安全,且私有(privacy_level == private)Agent 使用更宽松(lax=True)的校验标准——因为私有 Agent 只影响自己;
  • 模型档位控制:创建时若所选 chat_modelprice_tier 非 FREE 且用户无 premium 订阅,agent_chat_model 会被置为 None(回退默认模型),见 create_agent
  • 删除保护adelete_agent_by_slug 校验 agent.creator != user 则拒绝删除,并会连带清空该 Agent 名下的全部 Entry(知识条目)。

GET /agents/options 端点还暴露了 input_toolsoutput_modes 的人类可读描述(来自 command_descriptions_for_agent / mode_descriptions_for_agent 映射),前端 Agents 配置页即基于此渲染可选项。

6. Agent 知识绑定:原子事务如何复制向量条目

创建 Agent 时可同时传入 files 参数,将用户已有知识文件"挂"到该 Agent 名下,形成专属知识库。真实的数据操作在 atomic_update_agent(注意 @transaction.atomic 装饰器)中完成,流程是:

  1. update_or_create(slug, creator) 定位并落库 Agent 全部字段;
  2. 删除该 Agent 名下旧的 FileObjectEntry
  3. 从创建者个人的 FileObject/Entryagent=None)中筛选 file_name__in=files 的记录,bulk_create(FileObject 批 100、Entry 批 500)复制出新的、带 agent 指向的条目——注意向量(embeddings)是直接复制引用,不重新编码;
  4. 整段操作在同一事务内,失败整体回滚,避免"部分文件同步"的脏状态。

test_agents.py 中的测试用例印证了这条链路的正确性:

7. 小结与延伸阅读

Khoj 的 Agent 机制可以概括为一条主线:personality 定义"它是谁",chat_model + input_tools + output_modes 定义"它能做什么",files 定义"它知道什么",privacy_level + creator 定义"谁能用它"。自托管用户最常用的是 Admin 路径(server/admin/database/agent → Add Agent → 设置 public 与否 → 填写 personality),而集成方则应通过 /agents REST 端点完成同样的事情。

继续深入时,可按以下路径阅读源码:

登录后查看全文
热门项目推荐
相关项目推荐