mirror of
https://github.com/langchain-ai/llmanager.git
synced 2026-07-01 20:44:01 -04:00
feat: Expand reflection step to generate a summary then extract (#16)
This commit is contained in:
@@ -127,6 +127,7 @@ async function handleHumanResponse(
|
||||
args.args.status === state.answer.status
|
||||
? "explanationChanged"
|
||||
: "allChanged",
|
||||
reflectionsSummary: "",
|
||||
};
|
||||
|
||||
// The suggested action was edited. Send to reflection.
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "./types.js";
|
||||
import { fullReflection } from "./nodes/full-reflection.js";
|
||||
import { explanationReflection } from "./nodes/explanation-reflection.js";
|
||||
import { extractReflections } from "./nodes/extract-reflections.js";
|
||||
|
||||
/**
|
||||
* Routes the reflection based on the change type. If the changeType is
|
||||
@@ -32,9 +33,11 @@ const workflow = new StateGraph(ReflectionZodState, ReflectionZodConfiguration)
|
||||
})
|
||||
.addNode("full_reflection", fullReflection)
|
||||
.addNode("explanation_reflection", explanationReflection)
|
||||
.addNode("extract_reflections", extractReflections)
|
||||
.addEdge(START, "routeReflection")
|
||||
.addEdge("explanation_reflection", END)
|
||||
.addEdge("full_reflection", END);
|
||||
.addEdge("explanation_reflection", "extract_reflections")
|
||||
.addEdge("full_reflection", "extract_reflections")
|
||||
.addEdge("extract_reflections", END);
|
||||
|
||||
export const graph = workflow.compile();
|
||||
graph.name = "Reflection Graph";
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import { getReflections, putReflections } from "../../stores/reflection.js";
|
||||
import { getReflections } from "../../stores/reflection.js";
|
||||
import { ReflectionState, ReflectionUpdate } from "../types.js";
|
||||
import { z } from "zod";
|
||||
import { loadModelFromConfig } from "../../utils/model.js";
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
const EXPLANATION_REFLECTION_PROMPT = `You're an advanced AI assistant tasked with generating reflections on an incorrect explanation for a user request, even though the final answer was correct.
|
||||
const EXPLANATION_REFLECTION_PROMPT = `You're an advanced AI assistant tasked with generating a summary of your reflection on an incorrect explanation for a user request, even though the final answer was correct.
|
||||
A human manually reviewed the explanation and determined it was incorrect, despite the answer being correct.
|
||||
|
||||
The answer and explanation are part of a review process where an employee submits a request for approval, and given some approval and rejection criteria, you determined whether to approve or reject the request.
|
||||
@@ -35,7 +34,8 @@ Your new task is to do the following:
|
||||
2. Carefully examine the corrected explanation.
|
||||
3. Carefully examine the original reasoning you generated.
|
||||
4. Think deeply about why your explanation was wrong, even though your reasoning led to the correct final answer. How did the reasoning fail to translate into an accurate explanation? Compare your explanation to the human corrected explanation to identify the root cause.
|
||||
5. Generate clear, concise reflections which will allow you to avoid making the same mistake (generating an incorrect explanation despite a correct answer) in the future. Read the 'reflection-generation-rules' below for more details.
|
||||
4. Generate clear, concise thinking into exactly where your thought process went wrong, and how you can avoid making the same mistake in the future.
|
||||
5. Read the 'reflection-generation-rules' below for more details.
|
||||
|
||||
<reflection-generation-rules>
|
||||
1. Reflections must be concise, and direct.
|
||||
@@ -44,10 +44,12 @@ Your new task is to do the following:
|
||||
4. Reflections should be specific and actionable, focusing on improving the explanation generation process based on the reasoning.
|
||||
5. Reflections should be focused on the root cause of the error in explanation generation.
|
||||
6. Reflections should be written in the present tense, as they will be used to guide future decision-making.
|
||||
|
||||
You are not generating the exact reflections in this step, but rather a summary of your reflections to this error. In a future step you'll extract the specific reflections from this summary.
|
||||
</reflection-generation-rules>
|
||||
|
||||
With all of this in mind, please generate new reflections on your mistake to assist with future decision-making. You should generate at least one reflection, as you got the explanation wrong so something needs to be changed.
|
||||
However, you do not need to generate multiple unless you failed in multiple ways. This is very important as you do not want to generate bloated, and overly long reflections.`;
|
||||
With all of this in mind, please generate a summary of new reflections on your mistake to assist with future decision-making. You do not need to be overly verbose, the less the better. Your main goal is to figure out exactly what went wrong, and how you can avoid making the same mistake in the future.
|
||||
Think long and hard, go!`;
|
||||
|
||||
function buildReflectionPrompt(inputs: {
|
||||
explanation: string;
|
||||
@@ -82,48 +84,23 @@ export async function explanationReflection(
|
||||
reflections: reflections,
|
||||
});
|
||||
|
||||
const model = await loadModelFromConfig(config, {
|
||||
const modelWithTools = new ChatAnthropic({
|
||||
model: "claude-3-7-sonnet-latest",
|
||||
maxTokens: 4500,
|
||||
thinking: {
|
||||
type: "enabled",
|
||||
budget_tokens: 3072,
|
||||
},
|
||||
});
|
||||
|
||||
const modelWithTools = model.bindTools(
|
||||
[
|
||||
{
|
||||
name: "generate_reflections",
|
||||
schema: z.object({
|
||||
reflections: z
|
||||
.array(z.string())
|
||||
.describe(
|
||||
"New reflections on your mistake in generating the explanation. You can generate a single reflection, or multiple reflections if you failed in multiple ways.",
|
||||
),
|
||||
}),
|
||||
description:
|
||||
"Generate new reflections (or a single reflection) on your mistake in generating the explanation, which you can use in future decision-making to avoid the mistake you made in this instance.",
|
||||
},
|
||||
],
|
||||
{
|
||||
tool_choice: "generate_reflections",
|
||||
},
|
||||
);
|
||||
|
||||
const response = await modelWithTools.invoke([
|
||||
{ role: "human", content: prompt },
|
||||
{
|
||||
role: "human",
|
||||
content: prompt,
|
||||
},
|
||||
]);
|
||||
|
||||
const newReflections = response.tool_calls?.[0]?.args?.reflections as
|
||||
| string[]
|
||||
| undefined;
|
||||
if (!newReflections?.length) {
|
||||
throw new Error("No new reflections generated");
|
||||
}
|
||||
|
||||
await putReflections(config.store, config.configurable?.assistant_id, [
|
||||
...reflections,
|
||||
...newReflections,
|
||||
]);
|
||||
|
||||
return {};
|
||||
return {
|
||||
reflectionsSummary: response.content as string,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import { loadModelFromConfig } from "../../utils/model.js";
|
||||
import { ReflectionState, ReflectionUpdate } from "../types.js";
|
||||
import { z } from "zod";
|
||||
import { getReflections, putReflections } from "../../stores/reflection.js";
|
||||
|
||||
const EXTRACT_REFLECTIONS_PROMPT = `You're an advanced AI assistant tasked with extracting reflections/memories from a larger reflection text you previously generated.
|
||||
|
||||
This piece of text was generated in response to an incorrect answer and explanation you provided in response to a user request.
|
||||
<instructions>
|
||||
Please examine the reflection text, and extract one (or more if many mistakes were made) concise, and direct reflection/memory to add to a list of reflections/memories.
|
||||
This list will be used in all future decision-making processes, so ensure the reflection/memory (or multiple) you generate will assist with future decision-making so that you don't make the same mistake twice.
|
||||
</instructions>
|
||||
|
||||
<reflection-generation-rules>
|
||||
1. Reflections must be concise, and direct.
|
||||
2. Reflections should never be duplicated. If the reflection you want to generate already exists in the 'all-reflections' section, do not generate it again.
|
||||
3. Avoid generating multiple, similar reflections, as this will bloat the list, and can lead to confusion.
|
||||
4. Reflections should be specific and actionable.
|
||||
5. Reflections should be focused on the root cause of the error, as to prevent the same mistake from happening again.
|
||||
6. Reflections should be written in the present tense, as they will be used to guide future decision-making.
|
||||
</reflection-generation-rules>
|
||||
|
||||
<reflection-text>
|
||||
{REFLECTION_TEXT}
|
||||
</reflection-text>
|
||||
|
||||
Here is your original (incorrect) answer and explanation:
|
||||
<original-incorrect-response>
|
||||
<explanation>
|
||||
{EXPLANATION}
|
||||
</explanation>
|
||||
<answer>
|
||||
{ANSWER}
|
||||
</answer>
|
||||
</original-incorrect-response>
|
||||
|
||||
And here is the human corrected answer, along with the human corrected explanation:
|
||||
<corrected-response>
|
||||
<explanation>
|
||||
{CORRECTED_EXPLANATION}
|
||||
</explanation>
|
||||
<answer>
|
||||
{CORRECTED_ANSWER}
|
||||
</answer>
|
||||
</corrected-response>
|
||||
|
||||
Here is the full list of reflections/memories you've generated in the past:
|
||||
<all-reflections>
|
||||
{REFLECTIONS}
|
||||
</all-reflections>
|
||||
|
||||
Please carefully read over all of the provided context, think slowly, and generate one (or more if many mistakes were made) concise, and direct reflection/memory to add to a list of reflections/memories.
|
||||
`;
|
||||
|
||||
function buildExtractReflectionsPrompt(inputs: {
|
||||
reflectionsSummary: string;
|
||||
explanation: string;
|
||||
answer: string;
|
||||
correctedExplanation: string;
|
||||
correctedAnswer: string;
|
||||
reflections: string[];
|
||||
}): string {
|
||||
return EXTRACT_REFLECTIONS_PROMPT.replace(
|
||||
"{REFLECTION_TEXT}",
|
||||
inputs.reflectionsSummary,
|
||||
)
|
||||
.replace("{EXPLANATION}", inputs.explanation)
|
||||
.replace("{ANSWER}", inputs.answer)
|
||||
.replace("{CORRECTED_EXPLANATION}", inputs.correctedExplanation)
|
||||
.replace("{CORRECTED_ANSWER}", inputs.correctedAnswer)
|
||||
.replace(
|
||||
"{REFLECTIONS}",
|
||||
inputs.reflections.map((r) => `<reflection>${r}</reflection>`).join(""),
|
||||
);
|
||||
}
|
||||
|
||||
export async function extractReflections(
|
||||
state: ReflectionState,
|
||||
config: LangGraphRunnableConfig,
|
||||
): Promise<ReflectionUpdate> {
|
||||
const model = await loadModelFromConfig(config, {
|
||||
temperature: 0,
|
||||
});
|
||||
|
||||
const modelWithTools = model.bindTools(
|
||||
[
|
||||
{
|
||||
name: "generate_reflections",
|
||||
schema: z.object({
|
||||
reflections: z
|
||||
.array(z.string())
|
||||
.describe(
|
||||
"New reflections on your mistake. You can generate a single reflection, or multiple reflections if you failed in multiple ways.",
|
||||
),
|
||||
}),
|
||||
description:
|
||||
"Generate new reflections (or a single reflection) on your mistake, which you can use in future decision-making to avoid the mistake you made in this instance.",
|
||||
},
|
||||
],
|
||||
{
|
||||
tool_choice: "generate_reflections",
|
||||
},
|
||||
);
|
||||
|
||||
const reflections = await getReflections(
|
||||
config.store,
|
||||
config.configurable?.assistant_id,
|
||||
);
|
||||
|
||||
const prompt = buildExtractReflectionsPrompt({
|
||||
explanation: state.originalAnswer.explanation,
|
||||
answer: state.originalAnswer.status,
|
||||
correctedExplanation: state.editedAnswer.explanation,
|
||||
correctedAnswer: state.editedAnswer.status,
|
||||
reflections: reflections,
|
||||
reflectionsSummary: state.reflectionsSummary,
|
||||
});
|
||||
|
||||
const response = await modelWithTools.invoke([
|
||||
{
|
||||
role: "human",
|
||||
content: prompt,
|
||||
},
|
||||
]);
|
||||
|
||||
const newReflections = response.tool_calls?.[0]?.args?.reflections as
|
||||
| string[]
|
||||
| undefined;
|
||||
if (!newReflections?.length) {
|
||||
throw new Error("No new reflections generated");
|
||||
}
|
||||
|
||||
await putReflections(config.store, config.configurable?.assistant_id, [
|
||||
...reflections,
|
||||
...newReflections,
|
||||
]);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import { getReflections, putReflections } from "../../stores/reflection.js";
|
||||
import { getReflections } from "../../stores/reflection.js";
|
||||
import { ReflectionState, ReflectionUpdate } from "../types.js";
|
||||
import { z } from "zod";
|
||||
import { loadModelFromConfig } from "../../utils/model.js";
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
const FULL_REFLECTION_PROMPT = `You're an advanced AI assistant tasked with generating reflections on a an incorrect answer to a user request.
|
||||
const FULL_REFLECTION_PROMPT = `You're an advanced AI assistant tasked with generating a summary of your reflection to an incorrect answer and explanation you provided.
|
||||
A human manually reviewed the answer, and the explanation and determined they were both incorrect.
|
||||
|
||||
The answer and explanation are apart of a review process, where an employee submits a request for approval, and given some approval and rejection criteria, you determined whether to approve or reject the request.
|
||||
@@ -39,7 +38,8 @@ Your new task is to do the following:
|
||||
1. Carefully examine your original (incorrect) answer and explanation.
|
||||
2. Carefully examine the corrected answer and explanation.
|
||||
3. Think deeply about where you went wrong, and how you can avoid making the same mistake in the future. Compare your explanation to the human corrected explanation to identify the root cause.
|
||||
4. Generate clear, concise reflections which will allow you to avoid making the same mistake in the future. Read the 'reflection-generation-rules' below for more details.
|
||||
4. Generate clear, concise thinking into exactly where your thought process went wrong, and how you can avoid making the same mistake in the future.
|
||||
5. Read the 'reflection-generation-rules' below for more details.
|
||||
|
||||
<reflection-generation-rules>
|
||||
1. Reflections must be concise, and direct.
|
||||
@@ -48,10 +48,12 @@ Your new task is to do the following:
|
||||
4. Reflections should be specific and actionable.
|
||||
5. Reflections should be focused on the root cause of the error, as to prevent the same mistake from happening again.
|
||||
6. Reflections should be written in the present tense, as they will be used to guide future decision-making.
|
||||
|
||||
You are not generating the exact reflections in this step, but rather a summary of your reflections to this error. In a future step you'll extract the specific reflections from this summary.
|
||||
</reflection-generation-rules>
|
||||
|
||||
With all of this in mind, please generate new reflections on your mistake to assist with future decision-making. You should generate at least one reflection, as you got this wrong so something needs to be changed.
|
||||
However, you do not need to generate multiple unless you failed in multiple ways. This is very important as you do not want to generate bloated, and overly long reflections.`;
|
||||
With all of this in mind, please generate a summary of new reflections on your mistake to assist with future decision-making. You do not need to be overly verbose, the less the better. Your main goal is to figure out exactly what went wrong, and how you can avoid making the same mistake in the future.
|
||||
Think long and hard, go!`;
|
||||
|
||||
function buildReflectionPrompt(inputs: {
|
||||
explanation: string;
|
||||
@@ -86,33 +88,15 @@ export async function fullReflection(
|
||||
reflections: reflections,
|
||||
});
|
||||
|
||||
const model = await loadModelFromConfig(config, {
|
||||
const modelWithTools = new ChatAnthropic({
|
||||
model: "claude-3-7-sonnet-latest",
|
||||
maxTokens: 4500,
|
||||
thinking: {
|
||||
type: "enabled",
|
||||
budget_tokens: 3072,
|
||||
},
|
||||
});
|
||||
|
||||
const modelWithTools = model.bindTools(
|
||||
[
|
||||
{
|
||||
name: "generate_reflections",
|
||||
schema: z.object({
|
||||
reflections: z
|
||||
.array(z.string())
|
||||
.describe(
|
||||
"New reflections on your mistake. You can generate a single reflection, or multiple reflections if you failed in multiple ways.",
|
||||
),
|
||||
}),
|
||||
description:
|
||||
"Generate new reflections (or a single reflection) on your mistake, which you can use in future decision-making to avoid the mistake you made in this instance.",
|
||||
},
|
||||
],
|
||||
{
|
||||
tool_choice: "generate_reflections",
|
||||
},
|
||||
);
|
||||
|
||||
const response = await modelWithTools.invoke([
|
||||
{
|
||||
role: "human",
|
||||
@@ -120,17 +104,7 @@ export async function fullReflection(
|
||||
},
|
||||
]);
|
||||
|
||||
const newReflections = response.tool_calls?.[0]?.args?.reflections as
|
||||
| string[]
|
||||
| undefined;
|
||||
if (!newReflections?.length) {
|
||||
throw new Error("No new reflections generated");
|
||||
}
|
||||
|
||||
await putReflections(config.store, config.configurable?.assistant_id, [
|
||||
...reflections,
|
||||
...newReflections,
|
||||
]);
|
||||
|
||||
return {};
|
||||
return {
|
||||
reflectionsSummary: response.content as string,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export const ReflectionZodState = Annotation.Root({
|
||||
status: "approved" | "rejected";
|
||||
}>(),
|
||||
changeType: Annotation<"explanationChanged" | "allChanged">(),
|
||||
reflectionsSummary: Annotation<string>(),
|
||||
});
|
||||
|
||||
export type ReflectionState = typeof ReflectionZodState.State;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 123 KiB |
Reference in New Issue
Block a user