Web UI¶
Web UI 是 lovia 自带的本地聊天应用,适合直接使用 Agent,或在开发自定义前端前验证功能。
一条命令启动¶
访问 http://127.0.0.1:8000,首次启动时配置一个模型即可。之后可用
lovia web --check 检查配置并探测端点,而不启动服务。
模型配置有两级,项目级文件存在时会整体覆盖用户级配置,而不是逐项合并:
| 路径 | 作用域 |
|---|---|
~/.lovia/config.json |
当前用户的默认配置 |
./.lovia/config.json |
当前项目的完整覆盖配置 |
密钥和聊天数据所在的 .lovia/ 会自动加入 .gitignore。在支持 Unix 权限的平台上,
配置文件只允许当前用户读写。
CLI 创建的默认 Agent 包含 Todo、Memory、时间与 HTTP Tool、Web 搜索、定时任务,以及以 当前目录为根的 coding 模式 Workspace。它还会自动读取:
AGENTS.md:作为 Agent instructions;./.agents/skills与~/.agents/skills:作为 Skills 目录(项目目录优先; 目录列表在设置 → 技能中管理);./.lovia/memory:作为 Memory 目录。
旧的 ./skills 不再自动加载;可以迁移到 ./.agents/skills,或在设置 → 技能中
添加。Web 搜索在配置 Tavily Key 后使用 Tavily,否则尝试可选的
DuckDuckGo 后端。
默认功能会产生主 Run 之外的模型调用:Memory 默认在每个已完成 Run 后提炼一次,定期整理时
再调用一次;标题和追问建议也各自独立调用。可以用 --no-memory、--no-followups 关闭对应功能,
或把辅助任务指派给更便宜的模型。Memory 的完整成本边界见记忆。
默认仅供本机使用
回环地址 127.0.0.1 默认不鉴权。绑定其他地址时必须设置 --token 或
LOVIA_WEB_TOKEN;未设置时服务会自动生成。持有 token 的客户端可以使用 Agent 的
全部能力,包括编辑文件和执行 Shell 命令,因此应把 token 当作密码。允许其他设备访问时,
建议同时使用 --readonly;多用户部署请参阅生产部署。
模型配置与切换¶
模型档案保存在 config.json 中。连接测试会真实检查端点可达性、认证、模型列表和上下文窗口;
端点未列出的模型 ID 仍可手动填写。
API Key 只写不读:服务端只返回是否已设置及脱敏提示,不会把完整密钥传回浏览器。配置更新会 整体校验、原子写入并立即生效,无需重启。
切换模型从下一条消息开始生效,包括旧对话的后续消息、定时任务和后台子 Agent;已经开始的 回复仍使用原模型。视觉理解以及标题、追问建议等辅助任务,可以分别指派给其他模型档案。
额外请求参数(高级)是一个 JSON 对象,原样合并进发给该端点的每个请求——即 provider 的
extra_body。推理相关的配置就靠它,按端点自己的
写法填,因为一个 OpenAI 兼容格式背后藏着许多方言:OpenAI、DeepSeek、Qwen 3.8 和 vLLM 用
{"reasoning_effort": "medium"};vLLM/SGLang 部署的 Qwen、GLM 用
{"chat_template_kwargs": {"enable_thinking": false}};DeepSeek 与智谱官方 API 用
{"thinking": {"type": "disabled"}};Anthropic 用 {"output_config": {"effort": "medium"}}。
值为 null 表示删除适配器本来会发的字段(拒绝 stream_options 的网关可写
{"stream_options": null})。不做任何转换,端点接受什么由端点决定——官方 API 会在下一条消息
时拒绝不认识的字段,vLLM 则可能静默忽略;对话里有没有思考痕迹才是真正的检验。编辑框下方的
快捷片段只负责写入这些形状,不代表模型支持。
经过这个档案的每一次调用都会带上这些字段——主回复、后台子 Agent、上下文压缩摘要,以及被指派为
视觉或辅助角色时的图片描述、标题和追问。同一端点想要第二套参数,就是第二个档案:复制在服务端
完成(连密钥一起,因为页面从不持有它),所以"标题不思考"就是复制一份、写上
enable_thinking: false、指派给辅助角色。思考模型需要输出空间:这里的 max_tokens 对该端点
优先于 --max-tokens,但上下文策略的输出预留不会跟着变。
搜索后端、Tavily Key 与 Skill 目录也保存在 config.json 中。模型连接、多模型档案、
角色指派、搜索和 Skills 配置没有对应的 CLI 参数;请通过设置页或直接维护配置文件。
Skills¶
设置 → 技能管理 Skill 目录——一个有序列表;每个 skill 是含 SKILL.md 的子目录
(详见 Skills)。skill 重名时靠前的目录优先。列表默认为
./.agents/skills 和 ~/.agents/skills;移除某个默认目录即禁用它,也可以添加任意
其他目录(支持 ~)。面板会展示每个目录的贡献——发现的 skills、解析问题、被遮蔽的
重名项;不存在的目录会被直接跳过,过期条目不会阻止服务启动。列表变更立即生效;
向已配置的目录里新增 skill 则无需任何操作。
加载自定义 Agent¶
创建 app.py:
from lovia import Agent
assistant = Agent(
name="assistant",
instructions="清晰回答,并在有助于提高准确性时使用工具。",
model="<model>",
)
然后运行:
--app MODULE:ATTR 接受一个 Agent、{name: agent} 映射,或由 create_app() 构建的应用
(也可以是返回其中任意一种的无参工厂函数)。应用会按构建时的配置原样运行,沿用自定义的认证、
存储和 UI 选项;CLI 仍负责 host、port、日志和启动信息。原本会传给 create_app() 的选项
(--token、--db、--title 等)会被忽略并给出警告。Python 部署和 ASGI 集成详见
Web 服务端。
界面支持 GitHub 风格 Markdown、代码高亮、Mermaid 和内嵌图片。默认 Agent 已知道这些能力;
自定义 Agent 不会自动获得相关提示。如果希望模型主动使用这些格式,可以加入 SURFACE_NOTE:
from lovia.web import SURFACE_NOTE
assistant = Agent(
name="assistant",
instructions="清晰回答。\n\n" + SURFACE_NOTE,
model="<model>",
)
图片与文件¶
附件会写入 Workspace 的 uploads/,消息中保存的是相对路径。因此,即使模型不能直接读取附件,
Agent 仍可通过 Workspace Tool 打开文件。--no-workspace 会同时关闭这条路径。
Markdown 图片可以直接引用 Workspace 内的文件—— 会显示该文件本身,
回复和文件面板的 Markdown 预览都是如此。路径先按文档自身所在目录解析,再按 Workspace 根目录解析;
读取走的是与预览相同的只读接口。SVG 也能显示,走的是该接口的附件形式:浏览器对图片子资源会忽略
Content-Disposition(此时 SVG 里的脚本被禁用),对导航则会遵守(此时脚本本会执行)——于是图能显示,
而 URL 本身只会下载。
链接([report](report.md))指向同一个接口:在回复中,浏览器能直接显示的文件(图片、PDF)会在
新标签页打开,其余文件直接下载,对话本身不会被导航掉;在文件面板内,同样的链接则在查看器中打开。
回复里的外部链接同样在新标签页打开。
图片是否内联发送由视觉配置决定:
- 官方 OpenAI 和 Anthropic 端点默认按支持视觉处理;其他视觉端点需要把该模型配置的视觉能力
设为“支持”(即
config.json中的"vision": "on")。 - 纯文本主模型可以把视觉角色指派给另一个模型配置。此时主模型通过
describe_imageTool 获得文字结果,图片原始数据不会写入主模型的对话历史。
单个文件默认不超过 25 MiB,可用 LOVIA_MAX_UPLOAD_MB 调整。带扩展名的文件受内置白名单限制;
LOVIA_UPLOAD_ALLOWED_EXT 可覆盖白名单,使用逗号或空格分隔,* 表示不限。
通过文件面板上传的文件不会自动附加到下一条消息。"最近"列表不列环境噪音(node_modules/、
venv/、__pycache__/、*.pyc)和 Agent 的临时目录 tmp/,"新文件"角标也只统计会出现在
"最近"里的写入——这只是展示规则:目录浏览显示所有目录,Agent 引用的任何路径(回复里 tmp/
下的图片、工具卡片的"在文件面板打开")只要 Agent 自己能读就能打开。删除聊天也不会删除
uploads/ 中的文件,需要由应用或用户清理。
后台进程属于聊天而不是单次 Run:Run 结束不会终止它们;删除聊天或停止 Web 服务时会统一清理, 服务重启后也不会恢复。更完整的生命周期见工作区。
图表¶
show_chart 工具可以在聊天中绘制交互式图表,支持折线、柱状、饼图、散点、热力图、K 线、
桑基图等 Apache ECharts 的系列类型。模型把 ECharts option
写成调用参数,卡片负责渲染;实时对话和重新打开会话时都会显示。lovia web 的默认 Agent
已带有这个工具;使用自己的 Agent 时,把工具加进去:tools=[show_chart](从 lovia.web 导入)。任何工具也都
可以产出图表:return ui_result("chart", option),直接用真实数据作图,不需要模型抄写数字
(见UI 组件)。如果工具的 option 来自模型(比如执行查询后把结果行放进
option 的 dataset),先用 validate_chart_option(option) 检查:它抛出与 show_chart 相同的
工具错误,模型可以据此修正 option 后重试。
图表标题显示为卡片标题,位于图表上方,不会与图例重叠。标题旁的工具栏(鼠标悬停时显示)可以 把图表下载为 PNG 或 SVG(包含标题)、把数据下载为 CSV(树图、桑基图、关系图没有表格结构, 下载为 JSON),也可以全屏查看。
须知:
- ECharts(约 1 MB,已随包内置)在出现第一张图时才加载,没有图表的会话不会请求它。
- 把聊天导出为 HTML 时,每张图表以 SVG 图片的形式包含在内。
- option 在绘制前会经过过滤:图片、链接、
graphic和toolbox组件、HTML 形式的 tooltip 都会被去掉;需要代码或地图数据的系列类型(custom、map)也不支持。 - 团队的作图约定(偏好的图表类型、单位、标题写法等)写进 instructions 或一个 Skill 即可, 不需要写代码。
- 配色和文字颜色都是 CSS 变量(
--lv-chart-1…--lv-chart-8、--lv-chart-text、--lv-chart-title、--lv-chart-axis、--lv-chart-grid),在自定义模板 的head块中覆盖即可匹配品牌风格。
表格¶
show_table 工具用交互式表格代替 Markdown 表格展示给用户:点击表头排序(再点一次倒序,第三次
恢复原顺序),行数较多时可以输入关键字筛选,每页 20 行翻页浏览。数字右对齐并按数值排序。
工具栏可以复制表格(制表符分隔,可直接粘贴到表格软件)、下载 CSV,或全屏查看;导出的都是当前
视图,也就是筛选、排序之后的结果。把聊天导出为 HTML 时,表格会以包含全部行的普通表格形式
包含在内。
lovia web 的默认 Agent 已带有这个工具;使用自己的 Agent 时,把工具加进去:tools=[show_table]
(从 lovia.web 导入)。更常用的做法
往往是让自己的工具返回 ui_result("table", {"title": ..., "columns": [...], "rows": [[...], ...]}):
行数据直接来自你的数据源(查询、API),模型不必逐个写出数字,更快、更省,也不会出错。单元格可以是
字符串、数字、布尔值或 null,按原样显示。表格不认识的键会被忽略,所以同一份 props 里还可以附带
给模型看的信息,比如总行数或生成这些数据的 SQL。结果很大时,可以用 put_ui_data 把行数据挡在
模型上下文之外:模型只看预览,表格仍显示全部行(见大块数据)。
页面¶
show_html 工具可以在聊天中直接显示一个交互式页面:计算器、模拟、自定义可视化,凡是图表和表格
做不到的都可以。模型写出一个自包含的页面(CSS 和 JavaScript 都内联),卡片在沙箱中运行它。
lovia web 的默认 Agent 已带有这个工具;使用自己的 Agent 时,把工具加进去:tools=[show_html]
(从 lovia.web 导入)。你自己的工具也可以返回 ui_result("html", {"html": page, "title": ...})。
页面能做什么、不能做什么:
- 访问不到应用,也连不上网络。页面运行在不透明源中(没有 cookie、存储,也碰不到聊天内容),
其安全策略拦下所有请求:没有
fetch、CDN 脚本、网络字体和远程图片。链接不会跳转。 - 可以通过 CSS 变量和聊天界面保持一致:
var(--lv-ink)、var(--lv-surface)、var(--lv-border)、var(--lv-accent)、var(--lv-chart-1)…var(--lv-chart-8),浅色和深色主题都适用。 - 按钮可以以用户身份追问:
lovia.send("按地区拆开看")。只有在页面内真实点击时才会生效。 - 卡片随页面内容变高,最多占据大半个屏幕;支持全屏查看和下载 HTML。
- 重新打开聊天时,页面要点击 运行 才会启动,这样陷入死循环的页面不会在每次打开时卡住聊天。 切换主题会重新加载页面。
- 导出的 HTML 不含脚本,因此只显示页面的源码。
常用 CLI 选项¶
除模型、搜索和 Skills 配置外,其余选项按“命令行参数 → 环境变量 → 默认值”解析。
| 命令行选项 | 环境变量 | 默认值 |
|---|---|---|
--host / --port |
LOVIA_HOST / LOVIA_PORT |
127.0.0.1 / 8000 |
--root-path |
LOVIA_ROOT_PATH |
无;代理发布应用时使用的路径前缀(详见) |
--token |
LOVIA_WEB_TOKEN |
回环地址无需设置;其他地址自动生成 |
--db |
LOVIA_DB |
./.lovia/<agent>.db |
--app MODULE:ATTR |
LOVIA_APP |
创建默认 Agent(或使用自己的 Agent、映射或应用) |
--memory-dir / --no-memory |
LOVIA_MEMORY_DIR |
./.lovia/memory |
--workspace,--readonly / --trusted / --no-workspace |
LOVIA_WORKSPACE、LOVIA_WORKSPACE_MODE |
.(coding 模式) |
--instructions-file |
LOVIA_INSTRUCTIONS_FILE |
若存在则使用 AGENTS.md |
--max-retries / --max-turns |
LOVIA_MAX_RETRIES / LOVIA_MAX_TURNS |
4 / 50 |
--max-tokens |
LOVIA_MAX_TOKENS |
沿用 Provider 的默认值;模型配置“额外请求参数”里的 max_tokens 优先 |
--title |
LOVIA_TITLE |
lovia |
--log-level |
LOVIA_LOG_LEVEL |
info |
--no-followups |
LOVIA_FOLLOWUPS |
追问建议默认开启 |
--no-subagents |
— | 后台子 Agent 默认开启 |
--check |
— | 检查模型配置并退出 |
完整列表以 lovia web --help 为准。
来自 Agent 的提问¶
默认 Agent 带有 ask_human Tool。等待中的问题保存在服务端,
所以刷新或重新连接不会丢失。默认 10 分钟无人回答时,调用会取消,模型收到 Tool 错误后继续;
这也避免定时任务和后台任务长期占用运行槽位。
自定义 Agent 需要把同一个 HumanChannel 同时交给 Tool 和 Web 应用:
from lovia import Agent
from lovia.tools import HumanChannel, ask_human
from lovia.web import create_app, serve
channel = HumanChannel()
agent = Agent(name="bot", model="<model>", tools=[ask_human(channel)])
serve(create_app(agent, question_channel=channel, question_timeout=600))
追问建议¶
追问建议来自一次独立模型调用,不会写入 Transcript。关闭它可以避免这次额外调用;服务端使用
--no-followups,也可以把辅助任务角色指派给更便宜的模型(见模型配置与切换)。
通过 create_app() 托管自定义 Agent 时,该功能默认关闭,需要显式开启,见
Web 服务端。
运行与连接的边界¶
Run 由服务端托管,刷新或关闭页面不会取消它;重新连接后会从服务端状态继续。显式停止 Run 时, 已经完成的 Turn 仍保留在 Session 中。
服务优雅关闭时会保留主 Run 的 Checkpoint,重启后可以恢复;审批和 SSE 订阅等进程内状态不会恢复。 Shell 后台进程和后台子 Agent 也不会随 Checkpoint 恢复。
Run 执行期间发送的消息有两种处理方式,按条决定:
- 排队(Enter):消息显示在输入框上方,等当前 Run 成功完成后作为单独的 Run 发送。多条排队消息逐条发送, 每条都等上一条的 Run 完成。Run 失败或被停止时队列会暂停,可以点「立即发送」或撤回消息继续。 排队消息只保存在当前浏览器标签页中:仅在该对话打开时发送,刷新页面后会丢失。
- 插话(⌥/Alt+Enter,或排队消息上的「插话」):作为当前 Run 下一 Turn 的追加指令;如果当前 Run 恰好结束,用 ⌥/Alt+Enter 发出的会按顺序进入新的 Run,从队列插话的则回到队首,照常排队。 插话没有收到应答(例如网络中断)时,它可能已经送达,所以不会自动重发:它停在队首并暂停,等你核对对话。
Run 执行期间也可以添加附件,它们随消息一起发送,无论排队还是插话。有附件还在上传时,「发送」会等上传完成。 排队消息还可以放回输入框编辑(输入框和附件栏都为空时,文字和附件一起放回),或者撤回。
分支对话¶
每条已完成的回复上都有 在新对话中分支:它新建一个对话,包含到这条回复为止的全部内容, 你可以从这里把对话引向另一个方向。从最后一条回复分支,就是复制整个对话。某条回复之后若有 仍在运行的 Run,这条回复要等该 Run 结束后才会出现分支按钮。分支复制的是服务端当时保存的 内容。原对话不受影响,新对话会链接回原对话,删除其中一个不影响另一个。
分支复制的是对话,不是工作区:分支点之后写入的文件保持当前状态。
让 agent “在新对话里”做某件事时,它可以自己新建对话(start_session)。点击工具卡片即可打开
新对话;新对话不带当前对话的任何内容,并会链接回发起它的对话。
后台子 Agent¶
lovia web 默认启用后台子 Agent,可用 --no-subagents 关闭。
默认子 Agent 保留 Skills、Todo、Tool 和 Workspace,但不加载 Scheduling、Memory 或 Subagents,
因此不会递归派生。
自定义 Agent 需要自行添加 Subagents Plugin。create_app() 会把使用默认执行方式的 Plugin
接入 Web 托管;可用 create_app(..., wire_subagents=False) 禁用。直接挂载
build_api_router 时,需要调用一次 wire_subagents(deps)。
每个后台任务都有独立 Session。任务完成后,报告会送回父对话:父 Run 仍在执行时进入下一 Turn; 父对话空闲时,服务端会自动启动一次 Run 处理报告。浏览器无需保持在线。
后台任务不属于父 Run,因此停止父 Run 不会停止它;删除父对话则会停止它的后台任务,并一并删除。等待审批超过 approval_timeout 时会自动拒绝;
服务重启后,尚未完成的后台任务不会恢复。
延伸阅读¶
- Web 服务端:Python API、生命周期和定时任务
- HTTP API:构建自己的前端
- 工具审批:审批流程及默认拒绝规则
- 示例:
26_web_serve.py