









如果你已经用过一些 LLM SDK(其实我只用过Langchain),你会发现一个共性问题:模型调用很快能写出来,但“像样的聊天界面 + 会话管理 + 上线部署”这三件事会很快把代码变复杂。
Chainlit就是专门解决这个问题的:用很少的 Python 代码把对话应用搭起来,并且保留足够的扩展能力。
好吧, 你可能说,我可以让AI生成前端呀, 但是吧, 一是它不一定符合你的需求, 二是它需要你去维护(维护很费成本的哦),三是完善的前端很费token呢。
当然啦,也可以直接使用langchain自带的部署功能,不过还需要注册个账户,还不知道后面会不会额外收费,总的来说感觉差了一点什么,可能这是大多数流行应用不用langchain的原因?
其实langsmith的功能是真的棒,可是我就是不想注册个账户而已.
其实除了选择Chainlit还有很多其他的方式接入其他前端方案,比如Streamlit或者将Langchain包装一下,使用fastapi提供兼容OpenAI接口的接口,这样就可以接入很多其他的前端方案了,因为大多数前端方案都支持OpenAI接口。但是吧,还要维护一个前端项目,很烦人呢,所以我选择了Chainlit,如果你想快速给你的模型接入一个前端,你可以考虑一下Chainlit。
这篇文章我按“真正写项目”的顺序拆成 5 个部分,跟着走一遍,你可以从 0 到 1 跑出一个能用、能迭代、能上线的版本。
为了简单期间,大多数示例都是不接入大模型的,最后会介绍如何接入大模型,接入大模型是一件很简单的事情。总不能只有API KEY才能跑代码,是吧.
先别想太多,先把服务跑起来。
个人推荐使用uv管理Python项目依赖,避免污染全局Python, 所以后面的命令都是使用uv开头的命令。
这个命令会拉起一个官方示例页面,能打开就说明安装没问题。
新建 app.py:
import chainlit as cl
@cl.on_message
async def main(message: cl.Message):
"""处理用户消息并返回最小响应。"""
await cl.Message(content=f"收到你的消息了:{message.content}").send()
启动:
说明:
-w 会开启热更新,改代码后自动重载,开发体验会好很多。http://localhost:8000。一个对话机器人主要的就是对话,所以有个on_message很合理,是不!
就像一个http服务器,用户发送消息,服务器返回消息。只是入口只有一个,就是on_message。
很多同学一开始把所有逻辑都塞进 on_message,短期能跑,后面就会乱。
正确姿势是把逻辑按生命周期拆开。
import chainlit as cl
# 窗口打开就给用户发条消息
# 一些资源的初始化可以放这里
@cl.on_chat_start
async def on_chat_start():
"""初始化会话状态,在用户建立新会话时触发。"""
cl.user_session.set("history", [{"role": "system", "content": "你是一个简洁的中文助手。"}])
await cl.Message(content="你好,我已经准备好了,你可以直接提问。").send()
# 回复就回复当前会话消息数
@cl.on_message
async def on_message(message: cl.Message):
"""接收用户消息并写入会话历史。"""
history = cl.user_session.get("history") or []
history.append({"role": "user", "content": message.content})
cl.user_session.set("history", history)
await cl.Message(content=f"当前会话消息数:{len(history)}").send()
# 收尾, 资源回收或日志记录可以放这里
@cl.on_chat_end
def on_chat_end():
"""会话结束时触发,用于资源回收或日志记录。"""
print("聊天会话结束。")
这里重点有 2 个:
on_chat_start 做初始化,不要在每次消息都初始化。cl.user_session 管当前用户会话状态,避免多用户数据串线。能回消息只是起点,真正好用还得有“正在思考中”的流式体验。
下面给一个通用流式写法(不绑定某个厂商 SDK):
import asyncio
import chainlit as cl
async def fake_llm_stream(text: str):
"""模拟模型按 token 流式输出。"""
for token in text:
await asyncio.sleep(0.1)
yield token + " "
@cl.on_message
async def stream_reply(message: cl.Message):
"""将模型输出以流式方式返回给前端。"""
msg = cl.Message(content="")
await msg.send()
async for token in fake_llm_stream(f"你刚刚说的是:{message.content}"):
await msg.stream_token(token)
await msg.update()
这段代码的价值在于:
你后续还可以接入:
AskUser 类输入组件做参数收集。Step 把中间推理过程展示出来,便于调试和可解释性展示。当项目从 Demo 进入多人协作,配置和启动参数必须规范。
# 本地开发 自动检测代码是否变动
chainlit run app.py -w
# 指定监听端口和IP地址, 服务器运行(不自动打开浏览器)
chainlit run app.py --headless --host 0.0.0.0 --port 8000
# 子路径部署(如 https://example.com/chainlit)
# 如果你想不想放在网站的根路径的话
chainlit run app.py -h --root-path /chainlit
几个实践建议:
--host 0.0.0.0, 不然从容器外映射端口是映射不上的哈!!!配置还有ssl参数啥的,应该没人在这里配置ssl证书吧。
# 假设你有一个Caddyfile,内容如下:
example.com {
reverse_proxy 127.0.0.1:8000
}
Chainlit 默认是公开应用。如果你要内网/企业场景,一定要做鉴权。
先设置环境变量:
export CHAINLIT_AUTH_SECRET="请替换成你自己的强随机字符串"
也可以用官方命令生成:
import chainlit as cl
@cl.password_auth_callback
def auth_callback(username: str, password: str):
"""校验用户名密码,成功时返回用户对象。"""
if username == "admin" and password == "123456":
return cl.User(identifier="admin", metadata={"role": "administrator"})
return None
上线时再补这几件事:
allow_origins。接入langchain还是很简单的,不过需要注意开启langchain的流式输出时,设置正确的参数,参考代码如下
@cl.on_message
async def on_message(message: cl.Message) -> None:
model_key = message.modes.get("model") or DEFAULT_MODEL_KEY
enable_web_search = message.modes.get("search") == "web"
payload = {
"question": message.content,
"model_key": model_key,
"enable_web_search": enable_web_search,
}
msg = cl.Message(content="")
for chunk in graph.stream(
payload,
stream_mode="messages",
version="v2",
config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()])):
message_chunk, _ = chunk["data"]
if isinstance(message_chunk, AIMessage) and message_chunk.content:
await msg.stream_token(message_chunk.content)
await msg.send()
注意的点如下:
stream_mode="messages",不然不能逐字输出, 等结果在输出体验超级差。version="v2",配合上面的参数虽然AI大大加快了写代码的速度,生成前端更不是问题,但是写一个前端和维护一个前端还是不一样的,如果后期不再维护或者修改,那么就直接生成吧,AI应该可以写的很漂亮,也可以自定义各种样式,抄各种显示效果。
但是吧,如果后期需要维护或者修改并且没有太多精力维护,那么就选择一个开源的产品吧,Chainlit实在太棒啦。
官方文档入口:
LangChain关于流式输出的说明:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。