昨天跑完最 naive 的 ReAct baseline,今天就來實作一個更進階版本 —— 加上 Reflection State。
這個版本我暫時稱作 ReFAct(硬塞F)
ref: reflextion https://arxiv.org/pdf/2303.11366

做法如上,就是請 LLM 根據 evaluation result,進行反思

論文中的實驗數據也明確表示了差異

由於整個系統是採用 State Pattern 設計,要加入一個新的狀態其實非常簡單。
class ReflectionState(State):
    async def run(self, memory: "Memory") -> AsyncIterator[str]:
        messages = await get_messages(memory)
        content, _ = await get_response(model_name=REFLECTION_MODEL, messages=messages)
        if content:
            for chunk in content:
                yield chunk
            await memory.update(
                [Message(role=Role.ASSISTANT, content=f"<reflection>{content}</reflection>")]
            )
    async def next_state(self, memory: "Memory") -> Enum:
        return ReFact.REASONING
在這裡,Reflection 的輸出會直接包在 <reflection></reflection> 標籤中附加進記憶體。
下次進入 Reasoning state 時,模型就能看到自己的反思內容,並根據它修正策略。
只要把 Action 的下一步改成 Reflection 即可:
class ActionState(State):
    async def run(self, memory: "Memory") -> AsyncIterator[str]:
        ...
    async def next_state(self, memory: "Memory") -> Enum:
        return ReFact.REFLECTION
最後在 net map 中註冊這個新狀態:
def create_net() -> dict[Enum, State]:
    from .action import ActionState
    from .answer import AnswerState
    from .reasoning import ReasoningState
    from .reflection import ReflectionState
    return {
        ReFact.REFLECTION: ReflectionState(),
        ReFact.REASONING: ReasoningState(),
        ReFact.ACTION: ActionState(),
        ReFact.ANSWER: AnswerState(),
    }

初步結果算是有趣。
很明顯看到比純 ReAct 好了一點
目前的 memory structure 還是單純一直 append message
明天來看一下 context engineering 相關的東西好了