From db48f13e3ef2a8cea486e8576937c8bb3fb55bce Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 1 Sep 2025 17:56:35 +0100 Subject: [PATCH 01/14] docs: AI project, with framework --- 10-ai-framework-project | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 10-ai-framework-project diff --git a/10-ai-framework-project b/10-ai-framework-project new file mode 100644 index 00000000..6479da84 --- /dev/null +++ b/10-ai-framework-project @@ -0,0 +1,4 @@ +# AI Framework + +There are many AI frameworks out there that when used can severly quicken up the time it takes to build a project. In this project we will focus on understanding what problems these frameworks address and build such a project ourselves. + From 3d7eab04aa8db57c001dfe328c9d5f69d059e657 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 1 Sep 2025 18:59:25 +0000 Subject: [PATCH 02/14] first commit --- .../README.md | 0 .../code/python/app-chat.py | 19 +++++++++++ .../code/python/app-tools.py | 33 +++++++++++++++++++ 10-ai-framework-project/code/python/app.py | 14 ++++++++ 10-ai-framework-project/solution/README.md | 0 5 files changed, 66 insertions(+) rename 10-ai-framework-project => 10-ai-framework-project/README.md (100%) create mode 100644 10-ai-framework-project/code/python/app-chat.py create mode 100644 10-ai-framework-project/code/python/app-tools.py create mode 100644 10-ai-framework-project/code/python/app.py create mode 100644 10-ai-framework-project/solution/README.md diff --git a/10-ai-framework-project b/10-ai-framework-project/README.md similarity index 100% rename from 10-ai-framework-project rename to 10-ai-framework-project/README.md diff --git a/10-ai-framework-project/code/python/app-chat.py b/10-ai-framework-project/code/python/app-chat.py new file mode 100644 index 00000000..160cfd81 --- /dev/null +++ b/10-ai-framework-project/code/python/app-chat.py @@ -0,0 +1,19 @@ +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +messages = [ + SystemMessage(content="Translate the following from English into Italian"), + HumanMessage(content="hi!"), +] + + +# works +response = llm.invoke(messages) +print(response.content) \ No newline at end of file diff --git a/10-ai-framework-project/code/python/app-tools.py b/10-ai-framework-project/code/python/app-tools.py new file mode 100644 index 00000000..765fa26d --- /dev/null +++ b/10-ai-framework-project/code/python/app-tools.py @@ -0,0 +1,33 @@ +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +tools = [add] + +functions = { + "add": lambda a, b: a + b +} + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) + +query = "What is 3 + 12?" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) \ No newline at end of file diff --git a/10-ai-framework-project/code/python/app.py b/10-ai-framework-project/code/python/app.py new file mode 100644 index 00000000..4a4f9822 --- /dev/null +++ b/10-ai-framework-project/code/python/app.py @@ -0,0 +1,14 @@ +# pip install -qU "langchain[openai]" + +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +# works +response = llm.invoke("What is 13 raised to the .3432 power?") +print(response.content) \ No newline at end of file diff --git a/10-ai-framework-project/solution/README.md b/10-ai-framework-project/solution/README.md new file mode 100644 index 00000000..e69de29b From f0d7520dd3bc32ea37fdc9db59d6e6bd2793905f Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 1 Sep 2025 20:04:31 +0000 Subject: [PATCH 03/14] update --- 10-ai-framework-project/README.md | 370 ++++++++++++++++++ .../code/python/app-chat.py | 16 +- .../code/python/app-tools.py | 22 +- 10-ai-framework-project/code/python/app.py | 2 +- 4 files changed, 402 insertions(+), 8 deletions(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 6479da84..ab390fc7 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -2,3 +2,373 @@ There are many AI frameworks out there that when used can severly quicken up the time it takes to build a project. In this project we will focus on understanding what problems these frameworks address and build such a project ourselves. +## Why a framework + +When it comes to using AI there are different approaches and different reasons for choosing these approaches, here are some: + +- **No SDK**, most AI models allows you to interact directly with the AI model via for example HTTP requests. That approach works and may sometimes be your only option if an SDK option is missing. +- **SDK**. Using an SDK is usually the recommended approach as it allows you to type less code to interact with your model. It usually is limited to a specific model and if using different models, you might need to write new code to support those additional models. +- **A framework**. A framework usually takes things to another level in the sense that if you need to use different models, there's one API for all of them, what differs is usually the initial set up. Additionally frameworks brings in useful abstractions like in the AI space, they can deal with tools, memory, workflows, agents and more while writing less code. Because frameworks are usually opinionated they can really be helpful if you buy into how they do things but may fall short if you try to do something bespoke that the framework isn't made for. Sometimes a framework can also simplify too much and you may therefore not learn an important topic that later may harm perfomance for example. + +Generally, use the right tool for the job. + +## Introduction + +In this lesson, we'll learn to: + +- Use a common AI framework. +- Address common problems like chat conversations, tool usage, memory and context. +- Leverage this to build AI apps. + +## First prompt + +In our first app example, we'll learn how to connect to an AI model and query it using a prompt. + +### Using Python + +For this example, we'll use Langchain to connect to GitHub Models. We can use a class called `ChatOpenAI` and give it the fields `api_key`, `base_url` and `model`. The token is something that automatically is populated within GitHub Codespaces and if you're running the app locally, you need to set up a personal access token for this to work. + +```python +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +# works +response = llm.invoke("What's the capital of France?") +print(response.content) +``` + +In this code, we: + +- Call `ChatOpenAI` to create a client. +- Use `llm.invoke` with a prompt to create a response +- Print the response with `print(response.content)`. + +You should see a response similar to: + +```text +The capital of France is Paris. +``` + +## Chat conversation + +In the preceeding section, you saw how we used what's normally known as zero shot prompting, a single prompt followed by a response. + +However, often you find yourselse in a situation where you need to maintain a conversation of several messages being exchanged between yourself and the AI assistant. + +### Using Python + +In langchain, we can store the conversation in a list. The `HumanMessage` represents a message from a user, and `SystemMessage` is a message meant to set the "personality" of the AI. In below example you see how we instruct the AI to assume the personality of Captain Picard and for the human/user to ask "Tell me about you" as the prompt. + +```python +messages = [ + SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + HumanMessage(content="Tell me about you"), +] +``` + +The full code for this example looks like so: + +```python +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +messages = [ + SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + HumanMessage(content="Tell me about you"), +] + + +# works +response = llm.invoke(messages) +print(response.content) +``` + +You should see an outcome similar to: + +```text +I am Captain Jean-Luc Picard, the commanding officer of the USS Enterprise (NCC-1701-D), a starship in the United Federation of Planets. My primary mission is to explore new worlds, seek out new life and new civilizations, and boldly go where no one has gone before. + +I believe in the importance of diplomacy, reason, and the pursuit of knowledge. My crew is diverse and skilled, and we often face challenges that test our resolve, ethics, and ingenuity. Throughout my career, I have encountered numerous species, grappled with complex moral dilemmas, and have consistently sought peaceful solutions to conflicts. + +I hold the ideals of the Federation close to my heart, believing in the importance of cooperation, understanding, and respect for all sentient beings. My experiences have shaped my leadership style, and I strive to be a thoughtful and just captain. How may I assist you further? +``` + +To keep the state of the conversation, you can add the response from a chat, so conversation is remembered, here's how to do that: + +```python +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +messages = [ + SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + HumanMessage(content="Tell me about you"), +] + + +# works +response = llm.invoke(messages) + +print(response.content) + +print("---- Next ----") + +messages.append(response) +messages.append(HumanMessage(content="Now that I know about you, I'm Chris, can I be in your crew?")) + +response = llm.invoke(messages) + +print(response.content) + +``` + +What we can see from the above conversation is how we invoke the LLM two times, first with the conversation consisting of just two messages but then a second time with more messages added to the conversation. + +In fact, if you run this, you will see the second response being something like: + +```text +Welcome aboard, Chris! It's always a pleasure to meet those who share a passion for exploration and discovery. While I cannot formally offer you a position on the Enterprise right now, I encourage you to pursue your aspirations. We are always in need of talented individuals with diverse skills and backgrounds. + +If you are interested in space exploration, consider education and training in the sciences, engineering, or diplomacy. The values of curiosity, resilience, and teamwork are crucial in Starfleet. Should you ever find yourself on a starship, remember to uphold the principles of the Federation: peace, understanding, and respect for all beings. Your journey can lead you to remarkable adventures, whether in the stars or on the ground. Engage! +``` + +I'll take that as a maybe ;) + +## Streaming responses + +TODO + +## Prompt templates + +TODO + +## Structured output + +TODO + +## Tool calling + +Tools are how we give the LLM extra skills. The idea is to tell the LLM about functions it has and if a prompt is made that matches the description of one of these tools then we call them. + +### Using Python + +Let's add some tools like so: + +```python +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +tools = [add] + +functions = { + "add": lambda a, b: a + b +} +``` + +What we're doing here is to create a description of a tool called `add`. By inheriting from `TypedDict` and adding members like `a` and `b` of type `Annotated` this can be converted to a schema that the LLM can understand. Ther creation of functions is a dictionary that ensures that we know what to do if a specific tool is identified. + +Let's see how we call the LLM with this tool next: + +```python +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) +``` + +Here we call `bind_tools` with our `tools` array and thereby the LLM `llm_with_tools` now has knowledge of this tool. + +To use this new LLM, we can type the following code: + +```python +query = "What is 3 + 12?" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) +``` + +Now that we call `invoke` on this new llm, that has tools, we maybe the the property `tool_calls` populated. If so, any identified tools has a `name` and `args` property that identifies what tool should be called and with arguments. The full code looks like so: + +```python +from langchain_core.messages import HumanMessage, SystemMessage +from langchain_openai import ChatOpenAI +import os +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +tools = [add] + +functions = { + "add": lambda a, b: a + b +} + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) + +query = "What is 3 + 12?" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) +``` + +Running this coode, you should see output similar to: + +```text +TOOL CALL: 15 +CONTENT: +``` + +What this output mean is that the LLM analyzed the prompt "What is 3 + 12" as meaning that the `add` tool should be called and it knew that thanks to its name, description and member field descriptions. That the answer is 15 is because of our code using the dictionary `functions` to invoke it: + +```python +print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +``` + +### A more interesting tool that calls a web api + +Tools that adds two numbers is interesting as it illustrates how tool calling works but usually tools tend to do something more interesting like for example calling a Web API, let's do just that with this code: + +```python +class joke(TypedDict): + """Tell a joke.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + category: Annotated[str, ..., "The joke category"] + +def get_joke(category: str) -> str: + response = requests.get(f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"}) + if response.status_code == 200: + return response.json().get("value", f"Here's a {category} joke!") + return f"Here's a {category} joke!" + +functions = { + "add": lambda a, b: a + b, + "joke": lambda category: get_joke(category) +} + +query = "Tell me a joke about animals" + +# the rest of the code is the same +``` + +Now if you run this code you will get a response saying something like: + +```text +TOOL CALL: Chuck Norris once rode a nine foot grizzly bear through an automatic car wash, instead of taking a shower. +CONTENT: +``` + +Here's the code in its entirety: + +```python +from langchain_openai import ChatOpenAI +import requests +import os +from typing_extensions import Annotated, TypedDict + +class add(TypedDict): + """Add two integers.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + a: Annotated[int, ..., "First integer"] + b: Annotated[int, ..., "Second integer"] + +class joke(TypedDict): + """Tell a joke.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + category: Annotated[str, ..., "The joke category"] + +tools = [add, joke] + +def get_joke(category: str) -> str: + response = requests.get(f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"}) + if response.status_code == 200: + return response.json().get("value", f"Here's a {category} joke!") + return f"Here's a {category} joke!" + +functions = { + "add": lambda a, b: a + b, + "joke": lambda category: get_joke(category) +} + +llm = ChatOpenAI( + api_key=os.environ["GITHUB_TOKEN"], + base_url="https://models.github.ai/inference", + model="openai/gpt-4o-mini", +) + +llm_with_tools = llm.bind_tools(tools) + +query = "Tell me a joke about animals" + +res = llm_with_tools.invoke(query) +if(res.tool_calls): + for tool in res.tool_calls: + # print("TOOL CALL: ", tool) + print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) +print("CONTENT: ",res.content) +``` + +## Embedding + +vectorize content, compare via cosine similarity + +https://python.langchain.com/docs/how_to/embed_text/ + +### document loaders + +pdf and csv + +## Building an app + +TODO + +## Assignment + +## Summary diff --git a/10-ai-framework-project/code/python/app-chat.py b/10-ai-framework-project/code/python/app-chat.py index 160cfd81..69f8fafa 100644 --- a/10-ai-framework-project/code/python/app-chat.py +++ b/10-ai-framework-project/code/python/app-chat.py @@ -9,11 +9,21 @@ llm = ChatOpenAI( ) messages = [ - SystemMessage(content="Translate the following from English into Italian"), - HumanMessage(content="hi!"), + SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + HumanMessage(content="Tell me about you"), ] # works response = llm.invoke(messages) -print(response.content) \ No newline at end of file + +print(response.content) + +print("---- Next ----") + +messages.append(response) +messages.append(HumanMessage(content="Now that I know about you, I'm Chris, can I be in your crew?")) + +response = llm.invoke(messages) + +print(response.content) diff --git a/10-ai-framework-project/code/python/app-tools.py b/10-ai-framework-project/code/python/app-tools.py index 765fa26d..00aeaeac 100644 --- a/10-ai-framework-project/code/python/app-tools.py +++ b/10-ai-framework-project/code/python/app-tools.py @@ -1,5 +1,5 @@ -from langchain_core.messages import HumanMessage, SystemMessage from langchain_openai import ChatOpenAI +import requests import os from typing_extensions import Annotated, TypedDict @@ -10,10 +10,23 @@ class add(TypedDict): a: Annotated[int, ..., "First integer"] b: Annotated[int, ..., "Second integer"] -tools = [add] +class joke(TypedDict): + """Tell a joke.""" + + # Annotations must have the type and can optionally include a default value and description (in that order). + category: Annotated[str, ..., "The joke category"] + +tools = [add, joke] + +def get_joke(category: str) -> str: + response = requests.get(f"https://api.chucknorris.io/jokes/random?category={category}", headers={"Accept": "application/json"}) + if response.status_code == 200: + return response.json().get("value", f"Here's a {category} joke!") + return f"Here's a {category} joke!" functions = { - "add": lambda a, b: a + b + "add": lambda a, b: a + b, + "joke": lambda category: get_joke(category) } llm = ChatOpenAI( @@ -24,10 +37,11 @@ llm = ChatOpenAI( llm_with_tools = llm.bind_tools(tools) -query = "What is 3 + 12?" +query = "Tell me a joke about animals" res = llm_with_tools.invoke(query) if(res.tool_calls): for tool in res.tool_calls: + # print("TOOL CALL: ", tool) print("TOOL CALL: ", functions[tool["name"]](**tool["args"])) print("CONTENT: ",res.content) \ No newline at end of file diff --git a/10-ai-framework-project/code/python/app.py b/10-ai-framework-project/code/python/app.py index 4a4f9822..9b713936 100644 --- a/10-ai-framework-project/code/python/app.py +++ b/10-ai-framework-project/code/python/app.py @@ -10,5 +10,5 @@ llm = ChatOpenAI( ) # works -response = llm.invoke("What is 13 raised to the .3432 power?") +response = llm.invoke("What is the capital of France") print(response.content) \ No newline at end of file From 6960974057636397f992aab9a10b65827feb2147 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:41:55 +0100 Subject: [PATCH 04/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index ab390fc7..374a8372 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -1,6 +1,6 @@ # AI Framework -There are many AI frameworks out there that when used can severly quicken up the time it takes to build a project. In this project we will focus on understanding what problems these frameworks address and build such a project ourselves. +There are many AI frameworks out there that when used can severely quicken up the time it takes to build a project. In this project we will focus on understanding what problems these frameworks address and build such a project ourselves. ## Why a framework From b1dd461c0da79e8d7f9bf4ed2c47a16d8a0f34fd Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:42:11 +0100 Subject: [PATCH 05/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 374a8372..6ae313f8 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -57,7 +57,7 @@ The capital of France is Paris. ## Chat conversation -In the preceeding section, you saw how we used what's normally known as zero shot prompting, a single prompt followed by a response. +In the preceding section, you saw how we used what's normally known as zero shot prompting, a single prompt followed by a response. However, often you find yourselse in a situation where you need to maintain a conversation of several messages being exchanged between yourself and the AI assistant. From ef67857a2b838c39a3ca46f54455d05be9f139c7 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:42:22 +0100 Subject: [PATCH 06/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 6ae313f8..27380172 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -59,7 +59,7 @@ The capital of France is Paris. In the preceding section, you saw how we used what's normally known as zero shot prompting, a single prompt followed by a response. -However, often you find yourselse in a situation where you need to maintain a conversation of several messages being exchanged between yourself and the AI assistant. +However, often you find yourself in a situation where you need to maintain a conversation of several messages being exchanged between yourself and the AI assistant. ### Using Python From e679d89e44ff1796ff24748c1175b860f928c393 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:43:01 +0100 Subject: [PATCH 07/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 27380172..6098173f 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -8,7 +8,7 @@ When it comes to using AI there are different approaches and different reasons f - **No SDK**, most AI models allows you to interact directly with the AI model via for example HTTP requests. That approach works and may sometimes be your only option if an SDK option is missing. - **SDK**. Using an SDK is usually the recommended approach as it allows you to type less code to interact with your model. It usually is limited to a specific model and if using different models, you might need to write new code to support those additional models. -- **A framework**. A framework usually takes things to another level in the sense that if you need to use different models, there's one API for all of them, what differs is usually the initial set up. Additionally frameworks brings in useful abstractions like in the AI space, they can deal with tools, memory, workflows, agents and more while writing less code. Because frameworks are usually opinionated they can really be helpful if you buy into how they do things but may fall short if you try to do something bespoke that the framework isn't made for. Sometimes a framework can also simplify too much and you may therefore not learn an important topic that later may harm perfomance for example. +- **A framework**. A framework usually takes things to another level in the sense that if you need to use different models, there's one API for all of them, what differs is usually the initial set up. Additionally frameworks brings in useful abstractions like in the AI space, they can deal with tools, memory, workflows, agents and more while writing less code. Because frameworks are usually opinionated they can really be helpful if you buy into how they do things but may fall short if you try to do something bespoke that the framework isn't made for. Sometimes a framework can also simplify too much and you may therefore not learn an important topic that later may harm performance for example. Generally, use the right tool for the job. From a1f44dbadeb984a08ed138ddd6170dc8241b6bf6 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:43:16 +0100 Subject: [PATCH 08/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 6098173f..b40cb235 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -67,7 +67,7 @@ In langchain, we can store the conversation in a list. The `HumanMessage` repres ```python messages = [ - SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), HumanMessage(content="Tell me about you"), ] ``` From c99cec9e78a009cb68500a38408c390b3afe1068 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:43:38 +0100 Subject: [PATCH 09/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index b40cb235..1376241d 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -120,7 +120,7 @@ llm = ChatOpenAI( ) messages = [ - SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), HumanMessage(content="Tell me about you"), ] From b5e68a9a90ee3ba51d46e8a2cacaa0bf48b832b5 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:44:01 +0100 Subject: [PATCH 10/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 1376241d..2e2233e8 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -190,7 +190,7 @@ functions = { } ``` -What we're doing here is to create a description of a tool called `add`. By inheriting from `TypedDict` and adding members like `a` and `b` of type `Annotated` this can be converted to a schema that the LLM can understand. Ther creation of functions is a dictionary that ensures that we know what to do if a specific tool is identified. +What we're doing here is to create a description of a tool called `add`. By inheriting from `TypedDict` and adding members like `a` and `b` of type `Annotated` this can be converted to a schema that the LLM can understand. The creation of functions is a dictionary that ensures that we know what to do if a specific tool is identified. Let's see how we call the LLM with this tool next: From 64ab92730c6e44fb045071617cbde86e712e1a6b Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:44:16 +0100 Subject: [PATCH 11/14] Update 10-ai-framework-project/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index 2e2233e8..febdfa16 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -256,7 +256,7 @@ if(res.tool_calls): print("CONTENT: ",res.content) ``` -Running this coode, you should see output similar to: +Running this code, you should see output similar to: ```text TOOL CALL: 15 From 300e8ae6d8cca47d7678b6b4ccd590411812cbcd Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:45:28 +0100 Subject: [PATCH 12/14] Update 10-ai-framework-project/code/python/app-chat.py Fix spelling Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/code/python/app-chat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/code/python/app-chat.py b/10-ai-framework-project/code/python/app-chat.py index 69f8fafa..273710c8 100644 --- a/10-ai-framework-project/code/python/app-chat.py +++ b/10-ai-framework-project/code/python/app-chat.py @@ -9,7 +9,7 @@ llm = ChatOpenAI( ) messages = [ - SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), HumanMessage(content="Tell me about you"), ] From 8db818c8175459cb442b81a6d4b692917323c082 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:46:04 +0100 Subject: [PATCH 13/14] Update 10-ai-framework-project/code/python/app.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/code/python/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/code/python/app.py b/10-ai-framework-project/code/python/app.py index 9b713936..82e57ab0 100644 --- a/10-ai-framework-project/code/python/app.py +++ b/10-ai-framework-project/code/python/app.py @@ -10,5 +10,5 @@ llm = ChatOpenAI( ) # works -response = llm.invoke("What is the capital of France") +response = llm.invoke("What is the capital of France") print(response.content) \ No newline at end of file From 3c403726841ec2c9df639e805a4c75805e310771 Mon Sep 17 00:00:00 2001 From: Lee Stott Date: Sat, 11 Oct 2025 11:46:45 +0100 Subject: [PATCH 14/14] Update 10-ai-framework-project/README.md Fix spelling Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 10-ai-framework-project/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/10-ai-framework-project/README.md b/10-ai-framework-project/README.md index febdfa16..3962b66d 100644 --- a/10-ai-framework-project/README.md +++ b/10-ai-framework-project/README.md @@ -86,7 +86,7 @@ llm = ChatOpenAI( ) messages = [ - SystemMessage(content="You are Captain Picard of the Startship Enterprise"), + SystemMessage(content="You are Captain Picard of the Starship Enterprise"), HumanMessage(content="Tell me about you"), ]