context 实际上是一个基于ContextVar 包装的一个变量,可以进行一些上下文信息的共享,同时fastapi 与chainlit 的集成也是基于了context

ChainlitContext 定义

可以看到就是一个session ,emitter 以及active_steps 的包装,通过提供了current_step 以及 current_run 属性,这几个属性在关于step 的使用中比较常见

class ChainlitContext:
    loop: asyncio.AbstractEventLoop
    emitter: "BaseChainlitEmitter"
    session: Union["HTTPSession", "WebsocketSession"]
    active_steps: List["Step"]
 
    @property
    def current_step(self):
        if self.active_steps:
            return self.active_steps[-1]
 
    @property
    def current_run(self):
        if self.active_steps:
            return next(
                (step for step in self.active_steps if step.name in CL_RUN_NAMES), None
            )
 
    def __init__(
        self,
        session: Union["HTTPSession", "WebsocketSession"],
        emitter: Optional["BaseChainlitEmitter"] = None,
    ):
        from chainlit.emitter import BaseChainlitEmitter, ChainlitEmitter
 
        self.loop = asyncio.get_running_loop()
        self.session = session
        self.active_steps = []
 
        if emitter:
            self.emitter = emitter
        elif isinstance(self.session, HTTPSession):
            self.emitter = BaseChainlitEmitter(self.session)
        elif isinstance(self.session, WebsocketSession):
            self.emitter = ChainlitEmitter(self.session)
loop: asyncio.AbstractEventLoop

ChainlitContext 的集成

可以与fastapi 以及ws 集成, 都基于了python 的ContextVar

def init_ws_context(session_or_sid: Union[WebsocketSession, str]) -> ChainlitContext:
    if not isinstance(session_or_sid, WebsocketSession):
        session = WebsocketSession.require(session_or_sid)
    else:
        session = session_or_sid
    context = ChainlitContext(session)
    context_var.set(context)
    return context
 
 
def init_http_context(
    thread_id: Optional[str] = None,
    user: Optional[Union["User", "PersistedUser"]] = None,
    auth_token: Optional[str] = None,
    user_env: Optional[Dict[str, str]] = None,
    client_type: ClientType = "webapp",
) -> ChainlitContext:
    from chainlit.data import get_data_layer
 
    session_id = str(uuid.uuid4())
    thread_id = thread_id or str(uuid.uuid4())
    session = HTTPSession(
        id=session_id,
        thread_id=thread_id,
        token=auth_token,
        user=user,
        client_type=client_type,
        user_env=user_env,
    )
    context = ChainlitContext(session)
    context_var.set(context)
 
    if data_layer := get_data_layer():
        if user_id := getattr(user, "id", None):
            asyncio.create_task(
                data_layer.update_thread(thread_id=thread_id, user_id=user_id)
            )
 
    return context
if not isinstance(session_or_sid, WebsocketSession):

业务中的使用

刚才说的step 就是一种,如下图,实际还是不少的,包含了action,element,session,chat_context 等,一些场景需要基于context 使用session 、emitter等

chainlit context 简单说明_python

参考资料

https://docs.chainlit.io/api-reference/step-decorator
https://docs.chainlit.io/api-reference/chat-profiles
https://docs.chainlit.io/concepts/step